Update as per latest changes in upstream MR
Element has been renamed to hlsmultivariantsink. While at it, allow testing H265 and MPEG-TS by specifying command line flag.
This commit is contained in:
parent
5806277012
commit
bcbc533368
|
@ -15,7 +15,7 @@
|
|||
height="480"
|
||||
data-setup="{}"
|
||||
>
|
||||
<source src="http://localhost:8000/master.m3u8" type="application/x-mpegURL" />
|
||||
<source src="http://localhost:8000/multivariant.m3u8" type="application/x-mpegURL" />
|
||||
<p class="vjs-no-js">
|
||||
To view this video please enable JavaScript, and consider upgrading to a
|
||||
web browser that
|
||||
|
|
165
src/main.rs
165
src/main.rs
|
@ -1,4 +1,4 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use clap::{ArgAction, Parser, Subcommand};
|
||||
use gst::glib;
|
||||
use gst::prelude::*;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -6,20 +6,24 @@ use std::str::FromStr;
|
|||
|
||||
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
|
||||
gst::DebugCategory::new(
|
||||
"gst-hlssink4",
|
||||
"gst-hlsmultivariantsink",
|
||||
gst::DebugColorFlags::empty(),
|
||||
Some("gst-hlssink4"),
|
||||
)
|
||||
});
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "gst-hlssink4")]
|
||||
#[command(name = "gst-hlsmutivariantsink")]
|
||||
#[command(version = "0.1")]
|
||||
#[command(about = "Code for testing hlssink4", long_about = None)]
|
||||
#[command(about = "Code for testing hlsmultivariantsink", long_about = None)]
|
||||
struct Cli {
|
||||
media_file_path: String,
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
#[arg(long, action=ArgAction::SetTrue)]
|
||||
h265: bool,
|
||||
#[arg(long, action=ArgAction::SetTrue)]
|
||||
mpegts: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
|
@ -108,7 +112,14 @@ fn file_source_bin(
|
|||
(audiotee, videotee)
|
||||
}
|
||||
|
||||
fn video_bin(width: u32, height: u32, fps: u32, bitrate: u32, iframe_only: bool) -> gst::Bin {
|
||||
fn video_bin(
|
||||
width: u32,
|
||||
height: u32,
|
||||
fps: u32,
|
||||
bitrate: u32,
|
||||
iframe_only: bool,
|
||||
h265: bool,
|
||||
) -> gst::Bin {
|
||||
let bin = gst::Bin::new();
|
||||
|
||||
let clocksync = gst::ElementFactory::make("clocksync").build().unwrap();
|
||||
|
@ -116,25 +127,39 @@ fn video_bin(width: u32, height: u32, fps: u32, bitrate: u32, iframe_only: bool)
|
|||
let videoscale = gst::ElementFactory::make("videoscale").build().unwrap();
|
||||
let videorate = gst::ElementFactory::make("videorate").build().unwrap();
|
||||
let capsfilter = gst::ElementFactory::make("capsfilter").build().unwrap();
|
||||
let x264enc = gst::ElementFactory::make("x264enc").build().unwrap();
|
||||
let h264_capsfilter = gst::ElementFactory::make("capsfilter").build().unwrap();
|
||||
let h264parse = gst::ElementFactory::make("h264parse").build().unwrap();
|
||||
let x26xenc = if h265 {
|
||||
gst::ElementFactory::make("x265enc").build().unwrap()
|
||||
} else {
|
||||
gst::ElementFactory::make("x264enc").build().unwrap()
|
||||
};
|
||||
let h26x_capsfilter = gst::ElementFactory::make("capsfilter").build().unwrap();
|
||||
let h26xparse = if h265 {
|
||||
gst::ElementFactory::make("h265parse").build().unwrap()
|
||||
} else {
|
||||
gst::ElementFactory::make("h264parse").build().unwrap()
|
||||
};
|
||||
let queue = gst::ElementFactory::make("queue").build().unwrap();
|
||||
|
||||
let caps = gst::Caps::from_str(format!("video/x-raw,width={width},height={height},framerate={fps}/1,pixel-aspect-ratio=1/1,format=I420").as_str()).unwrap();
|
||||
capsfilter.set_property("caps", caps);
|
||||
|
||||
let caps = gst::Caps::from_str("video/x-h264").unwrap();
|
||||
h264_capsfilter.set_property("caps", caps);
|
||||
let caps = if h265 {
|
||||
gst::Caps::from_str("video/x-h265").unwrap()
|
||||
} else {
|
||||
gst::Caps::from_str("video/x-h264").unwrap()
|
||||
};
|
||||
h26x_capsfilter.set_property("caps", caps);
|
||||
|
||||
x264enc.set_property("bitrate", bitrate);
|
||||
x264enc.set_property_from_str("speed-preset", "ultrafast");
|
||||
x264enc.set_property_from_str("tune", "zerolatency");
|
||||
x26xenc.set_property("bitrate", bitrate);
|
||||
x26xenc.set_property_from_str("speed-preset", "ultrafast");
|
||||
x26xenc.set_property_from_str("tune", "zerolatency");
|
||||
|
||||
if iframe_only {
|
||||
x264enc.set_property("key-int-max", 1);
|
||||
x26xenc.set_property("key-int-max", 1);
|
||||
} else if h265 {
|
||||
x26xenc.set_property("key-int-max", (fps * 2) as i32);
|
||||
} else {
|
||||
x264enc.set_property("key-int-max", fps * 2);
|
||||
x26xenc.set_property("key-int-max", fps * 2);
|
||||
}
|
||||
|
||||
bin.add_many([
|
||||
|
@ -143,9 +168,9 @@ fn video_bin(width: u32, height: u32, fps: u32, bitrate: u32, iframe_only: bool)
|
|||
&videoscale,
|
||||
&videorate,
|
||||
&capsfilter,
|
||||
&x264enc,
|
||||
&h264_capsfilter,
|
||||
&h264parse,
|
||||
&x26xenc,
|
||||
&h26x_capsfilter,
|
||||
&h26xparse,
|
||||
&queue,
|
||||
])
|
||||
.expect("failed to add the elements");
|
||||
|
@ -156,9 +181,9 @@ fn video_bin(width: u32, height: u32, fps: u32, bitrate: u32, iframe_only: bool)
|
|||
&videoscale,
|
||||
&videorate,
|
||||
&capsfilter,
|
||||
&x264enc,
|
||||
&h264_capsfilter,
|
||||
&h264parse,
|
||||
&x26xenc,
|
||||
&h26x_capsfilter,
|
||||
&h26xparse,
|
||||
&queue,
|
||||
])
|
||||
.expect("failed to link the elements");
|
||||
|
@ -237,14 +262,21 @@ fn multiple_audio_rendition_multiple_video_variant(
|
|||
pipeline: &gst::Pipeline,
|
||||
media_file_path: String,
|
||||
iframe: bool,
|
||||
h265: bool,
|
||||
mpegts: bool,
|
||||
) {
|
||||
let hlssink = gst::ElementFactory::make("hlssink4").build().unwrap();
|
||||
let hlssink = gst::ElementFactory::make("hlsmultivariantsink")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
hlssink.set_property("master-playlist-location", "hlssink/master.m3u8");
|
||||
hlssink.set_property(
|
||||
"multivariant-playlist-location",
|
||||
"hlssink/multivariant.m3u8",
|
||||
);
|
||||
hlssink.set_property_from_str("playlist-type", "event");
|
||||
hlssink.set_property("target-duration", 10u32);
|
||||
if iframe {
|
||||
hlssink.set_property_from_str("muxer-type", "mpegts")
|
||||
if mpegts || iframe {
|
||||
hlssink.set_property_from_str("muxer-type", "mpegts");
|
||||
}
|
||||
|
||||
pipeline.add(&hlssink).unwrap();
|
||||
|
@ -289,7 +321,7 @@ fn multiple_audio_rendition_multiple_video_variant(
|
|||
audio2_pad.set_property("alternate-rendition", r);
|
||||
audio_bin2_pad.link(&audio2_pad).unwrap();
|
||||
|
||||
let video_bin1 = video_bin(1920, 1080, 30, 2500, false);
|
||||
let video_bin1 = video_bin(1920, 1080, 30, 2500, false, h265);
|
||||
pipeline.add(&video_bin1).unwrap();
|
||||
let video_bin1_sinkpad = video_bin1.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -304,7 +336,7 @@ fn multiple_audio_rendition_multiple_video_variant(
|
|||
video1_pad.set_property("variant", v);
|
||||
video_bin1_pad.link(&video1_pad).unwrap();
|
||||
|
||||
let video_bin2 = video_bin(1280, 720, 30, 1500, false);
|
||||
let video_bin2 = video_bin(1280, 720, 30, 1500, false, h265);
|
||||
pipeline.add(&video_bin2).unwrap();
|
||||
let video_bin2_sinkpad = video_bin2.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -319,7 +351,7 @@ fn multiple_audio_rendition_multiple_video_variant(
|
|||
video2_pad.set_property("variant", v);
|
||||
video_bin2_pad.link(&video2_pad).unwrap();
|
||||
|
||||
let video_bin3 = video_bin(640, 360, 24, 700, false);
|
||||
let video_bin3 = video_bin(640, 360, 24, 700, false, h265);
|
||||
pipeline.add(&video_bin3).unwrap();
|
||||
let video_bin3_sinkpad = video_bin3.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -342,12 +374,20 @@ fn multiple_audio_rendition_multiple_video_variant(
|
|||
fn multiple_audio_rendition_single_video_variant(
|
||||
pipeline: &gst::Pipeline,
|
||||
media_file_path: String,
|
||||
h265: bool,
|
||||
mpegts: bool,
|
||||
) {
|
||||
let hlssink = gst::ElementFactory::make("hlssink4").build().unwrap();
|
||||
|
||||
hlssink.set_property("master-playlist-location", "hlssink/master.m3u8");
|
||||
hlssink.set_property(
|
||||
"multivariant-playlist-location",
|
||||
"hlssink/multivariant.m3u8",
|
||||
);
|
||||
hlssink.set_property_from_str("playlist-type", "event");
|
||||
hlssink.set_property("target-duration", 10u32);
|
||||
if mpegts {
|
||||
hlssink.set_property_from_str("muxer-type", "mpegts");
|
||||
}
|
||||
|
||||
pipeline.add(&hlssink).unwrap();
|
||||
|
||||
|
@ -410,7 +450,7 @@ fn multiple_audio_rendition_single_video_variant(
|
|||
audio3_pad.set_property("alternate-rendition", r);
|
||||
audio_bin3_pad.link(&audio3_pad).unwrap();
|
||||
|
||||
let video_bin1 = video_bin(1920, 1080, 30, 2500, false);
|
||||
let video_bin1 = video_bin(1920, 1080, 30, 2500, false, h265);
|
||||
pipeline.add(&video_bin1).unwrap();
|
||||
let video_bin1_sinkpad = video_bin1.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -429,12 +469,20 @@ fn multiple_audio_rendition_single_video_variant(
|
|||
fn single_audio_rendition_multiple_video_variant(
|
||||
pipeline: &gst::Pipeline,
|
||||
media_file_path: String,
|
||||
h265: bool,
|
||||
mpegts: bool,
|
||||
) {
|
||||
let hlssink = gst::ElementFactory::make("hlssink4").build().unwrap();
|
||||
|
||||
hlssink.set_property("master-playlist-location", "hlssink/master.m3u8");
|
||||
hlssink.set_property(
|
||||
"multivariant-playlist-location",
|
||||
"hlssink/multivariant.m3u8",
|
||||
);
|
||||
hlssink.set_property_from_str("playlist-type", "event");
|
||||
hlssink.set_property("target-duration", 10u32);
|
||||
if mpegts {
|
||||
hlssink.set_property_from_str("muxer-type", "mpegts");
|
||||
}
|
||||
|
||||
pipeline.add(&hlssink).unwrap();
|
||||
|
||||
|
@ -459,7 +507,7 @@ fn single_audio_rendition_multiple_video_variant(
|
|||
audio1_pad.set_property("alternate-rendition", r);
|
||||
audio_bin1_pad.link(&audio1_pad).unwrap();
|
||||
|
||||
let video_bin1 = video_bin(1920, 1080, 30, 2500, false);
|
||||
let video_bin1 = video_bin(1920, 1080, 30, 2500, false, h265);
|
||||
pipeline.add(&video_bin1).unwrap();
|
||||
let video_bin1_sinkpad = video_bin1.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -474,7 +522,7 @@ fn single_audio_rendition_multiple_video_variant(
|
|||
video1_pad.set_property("variant", v);
|
||||
video_bin1_pad.link(&video1_pad).unwrap();
|
||||
|
||||
let video_bin2 = video_bin(1280, 720, 30, 1500, false);
|
||||
let video_bin2 = video_bin(1280, 720, 30, 1500, false, h265);
|
||||
pipeline.add(&video_bin2).unwrap();
|
||||
let video_bin2_sinkpad = video_bin2.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -489,7 +537,7 @@ fn single_audio_rendition_multiple_video_variant(
|
|||
video2_pad.set_property("variant", v);
|
||||
video_bin2_pad.link(&video2_pad).unwrap();
|
||||
|
||||
let video_bin3 = video_bin(640, 360, 24, 700, false);
|
||||
let video_bin3 = video_bin(640, 360, 24, 700, false, h265);
|
||||
pipeline.add(&video_bin3).unwrap();
|
||||
let video_bin3_sinkpad = video_bin3.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -508,10 +556,14 @@ fn single_audio_rendition_multiple_video_variant(
|
|||
fn single_audio_only_variant_multiple_video_variant_with_audio_video_muxed(
|
||||
pipeline: &gst::Pipeline,
|
||||
media_file_path: String,
|
||||
h265: bool,
|
||||
) {
|
||||
let hlssink = gst::ElementFactory::make("hlssink4").build().unwrap();
|
||||
|
||||
hlssink.set_property("master-playlist-location", "hlssink/master.m3u8");
|
||||
hlssink.set_property(
|
||||
"multivariant-playlist-location",
|
||||
"hlssink/multivariant.m3u8",
|
||||
);
|
||||
hlssink.set_property_from_str("playlist-type", "event");
|
||||
hlssink.set_property("target-duration", 10u32);
|
||||
hlssink.set_property_from_str("muxer-type", "mpegts");
|
||||
|
@ -520,7 +572,7 @@ fn single_audio_only_variant_multiple_video_variant_with_audio_video_muxed(
|
|||
|
||||
let (audiotee, videotee) = file_source_bin(pipeline, media_file_path);
|
||||
|
||||
let video_bin1 = video_bin(1920, 1080, 30, 2500, false);
|
||||
let video_bin1 = video_bin(1920, 1080, 30, 2500, false, h265);
|
||||
pipeline.add(&video_bin1).unwrap();
|
||||
let video_bin1_sinkpad = video_bin1.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -535,7 +587,7 @@ fn single_audio_only_variant_multiple_video_variant_with_audio_video_muxed(
|
|||
video1_pad.set_property("variant", v);
|
||||
video_bin1_pad.link(&video1_pad).unwrap();
|
||||
|
||||
let video_bin2 = video_bin(1280, 720, 30, 1500, false);
|
||||
let video_bin2 = video_bin(1280, 720, 30, 1500, false, h265);
|
||||
pipeline.add(&video_bin2).unwrap();
|
||||
let video_bin2_sinkpad = video_bin2.static_pad("sink").unwrap();
|
||||
let videotee_srcpad = videotee.request_pad_simple("src_%u").unwrap();
|
||||
|
@ -605,25 +657,48 @@ fn main() {
|
|||
match cli.command {
|
||||
Some(c @ Commands::MultipleAudioRenditionMultipleVideoVariant) => {
|
||||
println!("Generating HLS playlist for: {:?}", c);
|
||||
multiple_audio_rendition_multiple_video_variant(&pipeline, cli.media_file_path, false);
|
||||
multiple_audio_rendition_multiple_video_variant(
|
||||
&pipeline,
|
||||
cli.media_file_path,
|
||||
false,
|
||||
cli.h265,
|
||||
cli.mpegts,
|
||||
);
|
||||
}
|
||||
Some(c @ Commands::MultipleAudioRenditionMultipleVideoVariantWithIframe) => {
|
||||
println!("Generating HLS playlist for: {:?}", c);
|
||||
multiple_audio_rendition_multiple_video_variant(&pipeline, cli.media_file_path, true);
|
||||
multiple_audio_rendition_multiple_video_variant(
|
||||
&pipeline,
|
||||
cli.media_file_path,
|
||||
true,
|
||||
cli.h265,
|
||||
cli.mpegts,
|
||||
);
|
||||
}
|
||||
Some(c @ Commands::MultipleAudioRenditionSingleVideoVariant) => {
|
||||
println!("Generating HLS playlist for: {:?}", c);
|
||||
multiple_audio_rendition_single_video_variant(&pipeline, cli.media_file_path);
|
||||
multiple_audio_rendition_single_video_variant(
|
||||
&pipeline,
|
||||
cli.media_file_path,
|
||||
cli.h265,
|
||||
cli.mpegts,
|
||||
);
|
||||
}
|
||||
Some(c @ Commands::SingleAudioRenditionMultipleVideoVariant) => {
|
||||
println!("Generating HLS playlist for: {:?}", c);
|
||||
single_audio_rendition_multiple_video_variant(&pipeline, cli.media_file_path);
|
||||
single_audio_rendition_multiple_video_variant(
|
||||
&pipeline,
|
||||
cli.media_file_path,
|
||||
cli.h265,
|
||||
cli.mpegts,
|
||||
);
|
||||
}
|
||||
Some(c @ Commands::SingleAudioOnlyVariantMultipleVideoVariantWithAudioVideoMuxed) => {
|
||||
println!("Generating HLS playlist for: {:?}", c);
|
||||
single_audio_only_variant_multiple_video_variant_with_audio_video_muxed(
|
||||
&pipeline,
|
||||
cli.media_file_path,
|
||||
cli.h265,
|
||||
);
|
||||
}
|
||||
None => {
|
||||
|
@ -631,7 +706,13 @@ fn main() {
|
|||
"Generating HLS playlist for: {:?}",
|
||||
Commands::MultipleAudioRenditionMultipleVideoVariant
|
||||
);
|
||||
multiple_audio_rendition_multiple_video_variant(&pipeline, cli.media_file_path, false);
|
||||
multiple_audio_rendition_multiple_video_variant(
|
||||
&pipeline,
|
||||
cli.media_file_path,
|
||||
false,
|
||||
cli.mpegts,
|
||||
cli.h265,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue