Skip to content
Closed
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
506 changes: 313 additions & 193 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion native/vkvideo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ crate-type = ["cdylib"]

[dependencies]
rustler = "0.37.0"
termcolor = "1.4.1"
vk-video = { git = "https://github.com/software-mansion/smelter.git", features=["expose_parsers"] }
wgpu = "25.0.2"
wgpu = "28.0.0"
naga = { version = "28", features = ["termcolor"] }
10 changes: 1 addition & 9 deletions native/vkvideo/src/encoder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::ok;
use crate::Resource;
use crate::{ok, EncodedFrame, Resource};
use rustler::{Atom, Error, NifTaggedEnum, ResourceArc};
use rustler::{Binary, Env, NifStruct, NifUnitEnum, OwnedBinary};
use std::sync::Mutex;
Expand All @@ -12,13 +11,6 @@ pub struct EncoderResource {
pub height: u32,
}

#[derive(NifStruct)]
#[module = "Membrane.VKVideo.EncodedFrame"]
pub struct EncodedFrame<'a> {
pub payload: Binary<'a>,
pub pts_ns: Option<u64>,
}

#[derive(NifUnitEnum)]
pub enum EncoderTune {
LowLatency,
Expand Down
61 changes: 57 additions & 4 deletions native/vkvideo/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use decoder::{DecoderResource, RawFrame};
use encoder::{EncodedFrame, EncoderRateControl, EncoderResource, EncoderTune};
use encoder::{EncoderRateControl, EncoderResource, EncoderTune};
use rustler::{Atom, Binary, Env, Error, ResourceArc, Term};
use std::sync::Arc;
use vk_video::VulkanDevice;
use vk_video::{
parameters::{VulkanAdapterDescriptor, VulkanDeviceDescriptor},
VulkanDevice,
};

rustler::atoms! {
ok,
Expand Down Expand Up @@ -46,6 +49,13 @@ impl Resource {
}
}

#[derive(rustler::NifStruct)]
#[module = "Membrane.VKVideo.EncodedFrame"]
pub struct EncodedFrame<'a> {
pub payload: Binary<'a>,
pub pts_ns: Option<u64>,
}

#[allow(non_local_definitions)]
fn load(env: Env, _: Term) -> bool {
rustler::resource!(Resource, env)
Expand All @@ -55,11 +65,23 @@ fn load(env: Env, _: Term) -> bool {
fn create_device() -> Result<(Atom, ResourceArc<Resource>), Error> {
let instance = vk_video::VulkanInstance::new()
.map_err(|err| Error::RaiseTerm(Box::new(err.to_string())))?;

let adapter_descriptor = VulkanAdapterDescriptor {
supports_decoding: true,
supports_encoding: true,
compatible_surface: None,
};
let adapter = instance
.create_adapter(None)
.create_adapter(&adapter_descriptor)
.map_err(|err| Error::RaiseTerm(Box::new(err.to_string())))?;

let device_descriptor = VulkanDeviceDescriptor {
wgpu_features: wgpu::Features::empty(),
wgpu_limits: wgpu::Limits::default(),
wgpu_experimental_features: wgpu::ExperimentalFeatures::disabled(),
};
let device = adapter
.create_device(wgpu::Features::empty(), wgpu::Limits::default())
.create_device(&device_descriptor)
.map_err(|err| Error::RaiseTerm(Box::new(err.to_string())))?;

let device_resource = ResourceArc::new(Resource::Device(DeviceResource { device }));
Expand Down Expand Up @@ -128,4 +150,35 @@ fn destroy<'a>(env: Env<'a>, resource: ResourceArc<Resource>) -> Result<Atom, Er
Ok(ok())
}

// #[rustler::nif(schedule = "DirtyIo")]
// fn new_transcoder(
// env: Env,
// resource: ResourceArc<Resource>,
// width: u32,
// height: u32,
// frame_rate: (u32, u32),
// tune: EncoderTune,
// rate_control: EncoderRateControl,
// ) -> Result<(Atom, ResourceArc<Resource>), Error> {
// encoder::new(env, resource, width, height, frame_rate, tune, rate_control)
// }

// #[rustler::nif(schedule = "DirtyIo")]
// fn transcode<'a>(
// env: Env<'a>,
// resource: ResourceArc<Resource>,
// bytes: Binary,
// pts_ns: Option<u64>,
// ) -> Result<(Atom, EncodedFrame<'a>), Error> {
// encoder::encode(env, resource, bytes, pts_ns)
// }

// #[rustler::nif(schedule = "DirtyIo")]
// pub fn flush_transcoder(
// env: Env,
// resource: ResourceArc<Resource>,
// ) -> Result<(Atom, Vec<RawFrame>), Error> {
// transcoder::flush(env, resource)
// }

rustler::init!("Elixir.Membrane.VKVideo.Native", load = load);
Empty file.
3 changes: 3 additions & 0 deletions test/decoder_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ defmodule Decoder.Test do
import Membrane.Testing.Assertions
alias Membrane.Testing.{Pipeline, Sink}

@take_refs_snapshot System.get_env("TAKE_TEST_REFERENCES_SNAPSHOT", "") != ""

@framerate_numerator 25
@frame_duration_ms div(1000, @framerate_numerator)

Expand Down Expand Up @@ -61,6 +63,7 @@ defmodule Decoder.Test do

assert_end_of_stream(pid, :sink, :input)
Pipeline.terminate(pid)
if @take_refs_snapshot, do: File.write!(ref_path, File.read!(out_path))
assert File.read!(out_path) == File.read!(ref_path)
end
end
Expand Down
3 changes: 3 additions & 0 deletions test/encoder_native_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ defmodule Encoder.NativeTest do
use ExUnit.Case, async: false
alias Membrane.VKVideo.{DeviceServer, Native}

@take_refs_snapshot System.get_env("TAKE_TEST_REFERENCES_SNAPSHOT", "") != ""

@width 1280
@height 720
# number of bytes per sample is 1.5 since we use 420 chroma subsampling
Expand Down Expand Up @@ -61,6 +63,7 @@ defmodule Encoder.NativeTest do
encoded_frame.payload
end)

if @take_refs_snapshot, do: File.write!(ref_path, Enum.join(encoded_frames))
assert File.read!(ref_path) == Enum.join(encoded_frames)

Native.destroy(encoder_ref)
Expand Down
5 changes: 5 additions & 0 deletions test/encoder_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ defmodule Encoder.Test do
import Membrane.Testing.Assertions
alias Membrane.Testing.{Pipeline, Sink}

@take_refs_snapshot System.get_env("TAKE_TEST_REFERENCES_SNAPSHOT", "") != ""

@width 1280
@height 720
# number of bytes per sample is 1.5 since we use 420 chroma subsampling
Expand Down Expand Up @@ -122,6 +124,8 @@ defmodule Encoder.Test do

assert_end_of_stream(pid, :sink, :input)
Pipeline.terminate(pid)

if @take_refs_snapshot, do: File.write!(ref_path, File.read!(out_path))
assert File.read!(out_path) == File.read!(ref_path)
end

Expand Down Expand Up @@ -152,6 +156,7 @@ defmodule Encoder.Test do

Pipeline.terminate(pid)

if @take_refs_snapshot, do: File.write!(ref_path, File.read!(out_path))
assert File.read!(out_path) == File.read!(ref_path)
end
end
Expand Down
Binary file modified test/fixtures/ref-10-high_quality-constant_bitrate.h264
Binary file not shown.
Binary file modified test/fixtures/ref-10-high_quality-disabled.h264
Binary file not shown.
Binary file modified test/fixtures/ref-10-high_quality-encoder_default.h264
Binary file not shown.
Binary file modified test/fixtures/ref-10-high_quality-variable_bitrate.h264
Binary file not shown.
Binary file modified test/fixtures/ref-10-low_latency-constant_bitrate.h264
Binary file not shown.
Binary file modified test/fixtures/ref-10-low_latency-disabled.h264
Binary file not shown.
Binary file modified test/fixtures/ref-10-low_latency-encoder_default.h264
Binary file not shown.
Binary file modified test/fixtures/ref-10-low_latency-variable_bitrate.h264
Binary file not shown.
Loading