tracers: Add a tracer that dumps data flow into .pcap files

See documentation for more details

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/879>
This commit is contained in:
Thibault Saunier 2022-09-24 16:47:10 -03:00 committed by GStreamer Marge Bot
parent 86039dd5c1
commit a05ab37b49
6 changed files with 445 additions and 34 deletions

133
Cargo.lock generated
View file

@ -177,7 +177,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -219,7 +219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -241,7 +241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -258,7 +258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -1132,7 +1132,7 @@ checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -1416,7 +1416,7 @@ dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"quote 1.0.36",
"strsim 0.11.1",
"syn 2.0.70",
]
@ -1428,7 +1428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -1520,6 +1520,16 @@ dependencies = [
"serde",
]
[[package]]
name = "derive-into-owned"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "576fce04d31d592013a5887ba8d9c3830adff329e5096d7e1eb5e8e61262ca62"
dependencies = [
"quote 0.3.15",
"syn 0.11.11",
]
[[package]]
name = "diff"
version = "0.1.13"
@ -1677,6 +1687,15 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "etherparse"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "095ab548cf452be5813424558a18af88f0a620d0f4a3d8793aa09311a3b6fa5f"
dependencies = [
"arrayvec",
]
[[package]]
name = "event-listener"
version = "5.3.1"
@ -1885,7 +1904,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -2147,7 +2166,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro-crate",
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -2938,9 +2957,12 @@ name = "gst-plugin-tracers"
version = "0.14.0-alpha.1"
dependencies = [
"anyhow",
"atomic_refcell",
"etherparse",
"gst-plugin-version-helper",
"gstreamer",
"once_cell",
"pcap-file",
"regex",
"signal-hook",
]
@ -3569,7 +3591,7 @@ source = "git+https://github.com/gtk-rs/gtk4-rs?branch=master#f0f553dcee3862a889
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -3870,7 +3892,7 @@ dependencies = [
"httpdate",
"itoa",
"pin-project-lite",
"socket2 0.4.10",
"socket2 0.5.7",
"tokio",
"tower-service",
"tracing",
@ -4137,7 +4159,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -4882,7 +4904,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -4979,7 +5001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -5176,6 +5198,17 @@ dependencies = [
"hmac 0.11.0",
]
[[package]]
name = "pcap-file"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ad13fed1a83120159aea81b265074f21d753d157dd16b10cc3790ecba40a341"
dependencies = [
"byteorder",
"derive-into-owned",
"thiserror",
]
[[package]]
name = "pem"
version = "3.0.4"
@ -5218,7 +5251,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -5352,7 +5385,7 @@ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 1.0.109",
"version_check",
]
@ -5364,7 +5397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"version_check",
]
@ -5392,7 +5425,7 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd"
dependencies = [
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -5436,7 +5469,7 @@ dependencies = [
"anyhow",
"itertools 0.12.1",
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -5558,6 +5591,12 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
[[package]]
name = "quote"
version = "1.0.36"
@ -6249,7 +6288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -6321,7 +6360,7 @@ checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703"
dependencies = [
"darling",
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -6346,7 +6385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -6450,7 +6489,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
dependencies = [
"quote",
"quote 1.0.36",
]
[[package]]
@ -6561,6 +6600,17 @@ version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
dependencies = [
"quote 0.3.15",
"synom",
"unicode-xid",
]
[[package]]
name = "syn"
version = "1.0.109"
@ -6578,7 +6628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"unicode-ident",
]
@ -6594,6 +6644,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]]
name = "synom"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
dependencies = [
"unicode-xid",
]
[[package]]
name = "system-configuration"
version = "0.5.1"
@ -6685,7 +6744,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -6697,7 +6756,7 @@ checksum = "5a3a0c1b477619de2a1bf72990195561a06f7b68bbf272cea676236ad7cfb9e8"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"quote 1.0.36",
"regex",
"syn 2.0.70",
]
@ -6730,7 +6789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -6826,7 +6885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -7002,7 +7061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -7168,6 +7227,12 @@ version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
[[package]]
name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
[[package]]
name = "untrusted"
version = "0.9.0"
@ -7359,7 +7424,7 @@ dependencies = [
"log",
"once_cell",
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
"wasm-bindgen-shared",
]
@ -7382,7 +7447,7 @@ version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [
"quote",
"quote 1.0.36",
"wasm-bindgen-macro-support",
]
@ -7393,7 +7458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
@ -7720,7 +7785,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]
@ -7731,7 +7796,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"quote 1.0.36",
"syn 2.0.70",
]

View file

@ -9603,6 +9603,7 @@
"tracers": {
"buffer-lateness": {},
"pad-push-timings": {},
"pcap-writer": {},
"pipeline-snapshot": {},
"queue-levels": {}
},

View file

@ -13,6 +13,9 @@ gst.workspace = true
anyhow = "1"
regex = "1"
once_cell.workspace = true
atomic_refcell = "0.1"
pcap-file = "1.1.1"
etherparse = "0.14.0"
[target.'cfg(unix)'.dependencies]
signal-hook = "0.3"

View file

@ -16,6 +16,7 @@ use gst::glib;
mod buffer_lateness;
mod pad_push_timings;
mod pcap_writer;
#[cfg(unix)]
mod pipeline_snapshot;
mod queue_levels;
@ -26,6 +27,7 @@ fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
queue_levels::register(plugin)?;
buffer_lateness::register(plugin)?;
pad_push_timings::register(plugin)?;
pcap_writer::register(plugin)?;
Ok(())
}

View file

@ -0,0 +1,320 @@
// Copyright (C) 2022 Thibault Saunier <tsaunier@igalia.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at
// <https://mozilla.org/MPL/2.0/>.
//
// SPDX-License-Identifier: MPL-2.0
/**
* tracer-pcap-writer:
* @short_description: Dumps pad dataflow into a `.pcap` file.
*
* This tracer provides an easy way to save data flowing in a specified pad using
* the [`pcap`](https://wiki.wireshark.org/Development/LibpcapFileFormat) format.
*
* It can also wrap the dataflow inside fake IpV4/UDP headers so those pcap can
* then be reused with the #pcapparse element.
*
* It can be used to easily record/replay some parts of a WebRTC session without
* requiring to modify the GStreamer pipeline.
*
* ## Parameters:
*
* - `output-dir` (string, default: "tracer_pcaps"): The directory where to save
* `.pcap` files
* - `fake-protocol` (['udp', 'none'], default: "udp"): the fake headers to add
* to packets
*
* ## Example:
*
* ```console
* $ GST_TRACERS=pcap-writer(target-factory=rtph264pay) gst-launch-1.0 videotestsrc num-buffers=15 ! x264enc tune=zerolatency ! video/x-h264,profile=constrained-baseline ! rtph264pay seqnum-offset=0 ! rtph264depay ! fakesink
* ```
*
* Then this can be replayed with:
*
* ```console
* $ gst-launch-1.0 filesrc location="tracer_pcaps/pipeline0>rtph264pay0>src.pcap" ! pcapparse ! \
* "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, profile-level-id=(string)42c015, a-framerate=(string)30" ! \
* rtph264depay ! avdec_h264 ! fakesink silent=false -v -m
* ```
*
* Since: plugins-rs-0.13.0
*/
use pcap_file::pcap;
use etherparse::PacketBuilder;
use std::collections::{HashMap, HashSet};
use std::fs::{create_dir_all, File};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use atomic_refcell::AtomicRefCell;
use gst::glib;
use gst::prelude::*;
use gst::subclass::prelude::*;
use once_cell::sync::Lazy;
static MAX_PACKET_LEN: usize = 65535;
static MAX_FAKE_HEADERS_LEN: usize = 54;
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"pcap-writer",
gst::DebugColorFlags::empty(),
Some("pcap writer tracer"),
)
});
#[derive(Debug)]
struct Settings {
output_dir: PathBuf,
target_factory: Option<String>,
pad_path: Option<String>,
fake_protocol: FakeProtocol,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, glib::Enum)]
#[enum_type(name = "GstPcapWriterFakeProtocol")]
pub enum FakeProtocol {
Udp,
None,
}
impl Default for Settings {
fn default() -> Self {
Self {
output_dir: Path::new("tracer_pcaps").to_path_buf(),
target_factory: None,
pad_path: None,
fake_protocol: FakeProtocol::Udp,
}
}
}
impl Settings {
fn update_from_params(&mut self, obj: &super::PcapWriter, params: String) {
let s = match gst::Structure::from_str(&format!("pcap-writer-settings,{}", params)) {
Ok(s) => s,
Err(err) => {
gst::warning!(CAT, obj = obj, "failed to parse tracer parameters: {}", err);
return;
}
};
if let Ok(output_dir) = s.get::<&str>("output-dir") {
gst::log!(CAT, obj = obj, "pcap dumpdir= {}", output_dir);
self.output_dir = Path::new(output_dir).to_path_buf();
}
self.pad_path = s.get("pad-path").ok();
if let Ok(protocol) = s.get("fake-protocol") {
match glib::Value::deserialize(protocol, FakeProtocol::static_type()) {
Ok(protocol) => self.fake_protocol = protocol.get().unwrap(),
Err(err) => {
gst::warning!(CAT, obj = obj, "failed to parse fake-protocol: {}", err);
}
}
}
self.target_factory = s.get("target-factory").ok();
}
}
struct Writer {
writer: pcap::PcapWriter<File>,
buf: Vec<u8>,
protocol: FakeProtocol,
}
impl Writer {
fn new(file: File, protocol: FakeProtocol) -> Self {
Self {
writer: pcap::PcapWriter::new(file).expect("Error writing pcap"),
buf: Vec::<u8>::with_capacity(MAX_PACKET_LEN + MAX_FAKE_HEADERS_LEN),
protocol,
}
}
fn write(&mut self, buffer: &gst::BufferRef) -> Result<(), anyhow::Error> {
if buffer.size() > MAX_PACKET_LEN {
anyhow::bail!("Maximum size of packet is {MAX_PACKET_LEN}");
}
let map = buffer.map_readable()?;
if matches!(self.protocol, FakeProtocol::None) {
self.writer.write(
0,
buffer
.pts()
.unwrap_or(gst::ClockTime::from_seconds(0))
.nseconds() as u32,
map.as_slice(),
map.len() as u32,
)?;
return Ok(());
}
/* Add fake Ethernet/IP/UDP encapsulation for this packet */
/* FIXME: Make Ips configurable? */
let builder = PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])
.ipv4([192, 168, 1, 1], [192, 168, 1, 2], 20)
.udp(21, 1234);
let size = builder.size(map.size());
self.buf.clear();
builder.write(&mut self.buf, map.as_slice()).unwrap();
self.writer.write(
0,
buffer
.pts()
.unwrap_or(gst::ClockTime::from_seconds(0))
.nseconds() as u32,
&self.buf,
size as u32,
)?;
Ok(())
}
}
#[derive(Default)]
pub struct PcapWriter {
settings: AtomicRefCell<Settings>,
pads: Mutex<HashMap<usize, Arc<Mutex<Writer>>>>,
ignored: Mutex<HashSet<usize>>,
}
#[glib::object_subclass]
impl ObjectSubclass for PcapWriter {
const NAME: &'static str = "GstPcapWriter";
type Type = super::PcapWriter;
type ParentType = gst::Tracer;
}
impl ObjectImpl for PcapWriter {
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
let mut settings = Settings::default();
if let Some(params) = obj.property::<Option<String>>("params") {
settings.update_from_params(&obj, params);
}
if settings.target_factory.is_some() || settings.pad_path.is_some() {
if let Err(err) = create_dir_all(&settings.output_dir) {
gst::error!(
CAT,
"Could not create output dir, not writing pcaps: {err:?}"
)
} else {
self.register_hook(TracerHook::PadPushPre);
self.register_hook(TracerHook::PadPushListPre);
}
} else {
gst::warning!(
CAT,
obj = obj,
"'pcap-writer' enabled without specifying 'target-factory' or 'pad-path' parameters. Not writing pcaps."
);
}
*self.settings.borrow_mut() = settings;
}
}
impl GstObjectImpl for PcapWriter {}
fn pad_is_wanted(pad: &gst::Pad, settings: &Settings) -> bool {
if let Some(factory_name) = settings.target_factory.as_ref() {
return pad.parent().map_or(false, |p| {
p.downcast::<gst::Element>().map_or(false, |e| {
e.factory().map_or(false, |f| f.name() == *factory_name)
})
});
}
let mut element_name_pad_name = settings.pad_path.as_ref().unwrap().split(':');
let element_name = element_name_pad_name.next().unwrap();
let pad_name = element_name_pad_name.next();
if let Some(parent) = pad.parent() {
if parent.name() != element_name {
return false;
} else if let Some(pad_name) = pad_name {
return pad_name == pad.name();
}
return true;
}
false
}
impl TracerImpl for PcapWriter {
fn pad_push_list_pre(&self, _ts: u64, pad: &gst::Pad, blist: &gst::BufferList) {
for buffer in blist.iter() {
self.maybe_write_buffer(pad, buffer);
}
}
fn pad_push_pre(&self, _ts: u64, pad: &gst::Pad, buffer: &gst::Buffer) {
self.maybe_write_buffer(pad, buffer.as_ref());
}
}
impl PcapWriter {
fn maybe_write_buffer(&self, pad: &gst::Pad, buffer: &gst::BufferRef) {
if self
.ignored
.lock()
.unwrap()
.contains(&(pad.as_ptr() as usize))
{
return;
}
let mut pads = self.pads.lock().unwrap();
let writer = if let Some(writer) = pads.get(&(pad.as_ptr() as usize)) {
writer.clone()
} else if pad_is_wanted(pad, &self.settings.borrow()) {
let mut obj = pad.upcast_ref::<gst::Object>().clone();
let mut fname = obj.name().to_string();
while let Some(p) = obj.parent() {
fname = p.name().to_string() + ">" + &fname;
obj = p.clone();
}
fname.push_str(".pcap");
let outpath = self.settings.borrow().output_dir.join(fname);
gst::info!(CAT, obj = pad, "Writing pcap: {outpath:?}");
let outfile = File::create(outpath).expect("Error creating file");
let pcap_writer = Arc::new(Mutex::new(Writer::new(
outfile,
self.settings.borrow().fake_protocol,
)));
pads.insert(pad.as_ptr() as usize, pcap_writer.clone());
pcap_writer
} else {
self.ignored.lock().unwrap().insert(pad.as_ptr() as usize);
return;
};
drop(pads);
let mut writer = writer.lock().unwrap();
if let Err(err) = writer.write(buffer) {
gst::error!(CAT, "Error writing buffer: {err:?}");
}
}
}

View file

@ -0,0 +1,20 @@
// Copyright (C) 2022 Thibault Saunier <tsaunier@igalia.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at
// <https://mozilla.org/MPL/2.0/>.
//
// SPDX-License-Identifier: MPL-2.0
use gst::glib;
use gst::prelude::*;
mod imp;
glib::wrapper! {
pub struct PcapWriter(ObjectSubclass<imp::PcapWriter>) @extends gst::Tracer, gst::Object;
}
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
gst::Tracer::register(Some(plugin), "pcap-writer", PcapWriter::static_type())
}