Skip to content

Commit

Permalink
Added new_from_stream for encoder ⭐
Browse files Browse the repository at this point in the history
  • Loading branch information
NiiightmareXD committed Apr 11, 2024
1 parent 13954c9 commit 36a226a
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 47 deletions.
64 changes: 32 additions & 32 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "windows-capture"
version = "1.0.68"
version = "1.1.3"
authors = ["NiiightmareXD"]
edition = "2021"
description = "Fastest Windows Screen Capture Library For Rust 🔥"
Expand Down Expand Up @@ -48,10 +48,10 @@ windows = { version = "0.54.0", features = [
parking_lot = "0.12.1"

# Multithreading
rayon = "1.8.1"
rayon = "1.10.0"

# Error handling
thiserror = "1.0.57"
thiserror = "1.0.58"

[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Add this library to your `Cargo.toml`:

```toml
[dependencies]
windows-capture = "1.0.68"
windows-capture = "1.1.3"
```
or run this command

Expand Down
149 changes: 148 additions & 1 deletion src/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ use windows::{
},
Storage::{
FileAccessMode, StorageFile,
Streams::{Buffer, DataReader, InMemoryRandomAccessStream, InputStreamOptions},
Streams::{
Buffer, DataReader, IRandomAccessStream, InMemoryRandomAccessStream, InputStreamOptions,
},
},
};

Expand Down Expand Up @@ -340,6 +342,151 @@ impl VideoEncoder {
})
}

/// Creates a new `VideoEncoder` instance with the specified parameters.
///
/// # Arguments
///
/// * `encoder_type` - The type of video encoder to use.
/// * `encoder_quality` - The quality of the video encoder.
/// * `width` - The width of the video frames.
/// * `height` - The height of the video frames.
/// * `stream` - The stream where the encoded video will be saved.
///
/// # Returns
///
/// Returns a `Result` containing the `VideoEncoder` instance if successful, or a
/// `VideoEncoderError` if an error occurs.
pub fn new_from_stream<P: AsRef<Path>>(
encoder_type: VideoEncoderType,
encoder_quality: VideoEncoderQuality,
width: u32,
height: u32,
stream: IRandomAccessStream,
) -> Result<Self, VideoEncoderError> {
let media_encoding_profile = match encoder_type {
VideoEncoderType::Avi => {
MediaEncodingProfile::CreateAvi(VideoEncodingQuality(encoder_quality as i32))?
}
VideoEncoderType::Hevc => {
MediaEncodingProfile::CreateHevc(VideoEncodingQuality(encoder_quality as i32))?
}
VideoEncoderType::Mp4 => {
MediaEncodingProfile::CreateMp4(VideoEncodingQuality(encoder_quality as i32))?
}
VideoEncoderType::Wmv => {
MediaEncodingProfile::CreateWmv(VideoEncodingQuality(encoder_quality as i32))?
}
};

let video_encoding_properties = VideoEncodingProperties::CreateUncompressed(
&MediaEncodingSubtypes::Bgra8()?,
width,
height,
)?;

let video_stream_descriptor = VideoStreamDescriptor::Create(&video_encoding_properties)?;

let media_stream_source =
MediaStreamSource::CreateFromDescriptor(&video_stream_descriptor)?;
media_stream_source.SetBufferTime(TimeSpan::default())?;

let (frame_sender, frame_receiver) =
mpsc::channel::<Option<(SendDirectX<IDirect3DSurface>, TimeSpan)>>();

let starting = media_stream_source.Starting(&TypedEventHandler::<
MediaStreamSource,
MediaStreamSourceStartingEventArgs,
>::new(move |_, stream_start| {
let stream_start = stream_start
.as_ref()
.expect("MediaStreamSource Starting parameter was None This Should Not Happen.");

stream_start
.Request()?
.SetActualStartPosition(TimeSpan { Duration: 0 })?;
Ok(())
}))?;

let frame_notify = Arc::new((Mutex::new(false), Condvar::new()));

let sample_requested = media_stream_source.SampleRequested(&TypedEventHandler::<
MediaStreamSource,
MediaStreamSourceSampleRequestedEventArgs,
>::new({
let frame_receiver = frame_receiver;
let frame_notify = frame_notify.clone();

move |_, sample_requested| {
let sample_requested = sample_requested.as_ref().expect(
"MediaStreamSource SampleRequested parameter was None This Should Not Happen.",
);

let frame = match frame_receiver.recv() {
Ok(frame) => frame,
Err(e) => panic!("Failed to receive frame from frame sender: {e}"),
};

match frame {
Some((surface, timespan)) => {
let sample =
MediaStreamSample::CreateFromDirect3D11Surface(&surface.0, timespan)?;
sample_requested.Request()?.SetSample(&sample)?;
}
None => {
sample_requested.Request()?.SetSample(None)?;
}
}

let (lock, cvar) = &*frame_notify;
*lock.lock() = true;
cvar.notify_one();

Ok(())
}
}))?;

let media_transcoder = MediaTranscoder::new()?;
media_transcoder.SetHardwareAccelerationEnabled(true)?;

let transcode = media_transcoder
.PrepareMediaStreamSourceTranscodeAsync(
&media_stream_source,
&stream,
&media_encoding_profile,
)?
.get()?;

let error_notify = Arc::new(AtomicBool::new(false));
let transcode_thread = thread::spawn({
let error_notify = error_notify.clone();

move || -> Result<(), VideoEncoderError> {
let result = transcode.TranscodeAsync();

if result.is_err() {
error_notify.store(true, atomic::Ordering::Relaxed);
}

result?.get()?;

drop(media_transcoder);

Ok(())
}
});

Ok(Self {
first_timespan: None,
frame_sender,
sample_requested,
media_stream_source,
starting,
transcode_thread: Some(transcode_thread),
frame_notify,
error_notify,
})
}

/// Sends a video frame to the video encoder for encoding.
///
/// # Arguments
Expand Down
Loading

0 comments on commit 36a226a

Please sign in to comment.