1use std::{
2 fs::{self, File},
3 path::Path,
4 slice,
5 sync::{
6 Arc,
7 atomic::{self, AtomicBool},
8 mpsc,
9 },
10 thread::{self, JoinHandle},
11};
12
13use parking_lot::{Condvar, Mutex};
14use windows::{
15 Foundation::{TimeSpan, TypedEventHandler},
16 Graphics::{
17 DirectX::Direct3D11::IDirect3DSurface,
18 Imaging::{BitmapAlphaMode, BitmapEncoder, BitmapPixelFormat},
19 },
20 Media::{
21 Core::{
22 AudioStreamDescriptor, MediaStreamSample, MediaStreamSource,
23 MediaStreamSourceSampleRequestedEventArgs, MediaStreamSourceStartingEventArgs,
24 VideoStreamDescriptor,
25 },
26 MediaProperties::{
27 AudioEncodingProperties, ContainerEncodingProperties, MediaEncodingProfile,
28 MediaEncodingSubtypes, VideoEncodingProperties,
29 },
30 Transcoding::MediaTranscoder,
31 },
32 Security::Cryptography::CryptographicBuffer,
33 Storage::{
34 FileAccessMode, StorageFile,
35 Streams::{
36 Buffer, DataReader, IRandomAccessStream, InMemoryRandomAccessStream, InputStreamOptions,
37 },
38 },
39 core::{HSTRING, Interface},
40};
41
42use crate::{
43 d3d11::SendDirectX,
44 frame::{Frame, ImageFormat},
45 settings::ColorFormat,
46};
47
48#[derive(thiserror::Error, Eq, PartialEq, Clone, Debug)]
49pub enum ImageEncoderError {
50 #[error("This color format is not supported for saving as image")]
51 UnsupportedFormat,
52 #[error("Windows API Error: {0}")]
53 WindowsError(#[from] windows::core::Error),
54}
55
56pub struct ImageEncoder {
58 format: ImageFormat,
59 color_format: ColorFormat,
60}
61
62impl ImageEncoder {
63 #[must_use]
74 #[inline]
75 pub const fn new(format: ImageFormat, color_format: ColorFormat) -> Self {
76 Self {
77 format,
78 color_format,
79 }
80 }
81
82 #[inline]
98 pub fn encode(
99 &self,
100 image_buffer: &[u8],
101 width: u32,
102 height: u32,
103 ) -> Result<Vec<u8>, ImageEncoderError> {
104 let encoder = match self.format {
105 ImageFormat::Jpeg => BitmapEncoder::JpegEncoderId()?,
106 ImageFormat::Png => BitmapEncoder::PngEncoderId()?,
107 ImageFormat::Gif => BitmapEncoder::GifEncoderId()?,
108 ImageFormat::Tiff => BitmapEncoder::TiffEncoderId()?,
109 ImageFormat::Bmp => BitmapEncoder::BmpEncoderId()?,
110 ImageFormat::JpegXr => BitmapEncoder::JpegXREncoderId()?,
111 };
112
113 let stream = InMemoryRandomAccessStream::new()?;
114 let encoder = BitmapEncoder::CreateAsync(encoder, &stream)?.get()?;
115
116 let pixelformat = match self.color_format {
117 ColorFormat::Bgra8 => BitmapPixelFormat::Bgra8,
118 ColorFormat::Rgba8 => BitmapPixelFormat::Rgba8,
119 ColorFormat::Rgba16F => return Err(ImageEncoderError::UnsupportedFormat),
120 };
121
122 encoder.SetPixelData(
123 pixelformat,
124 BitmapAlphaMode::Premultiplied,
125 width,
126 height,
127 1.0,
128 1.0,
129 image_buffer,
130 )?;
131
132 encoder.FlushAsync()?.get()?;
133
134 let buffer = Buffer::Create(u32::try_from(stream.Size()?).unwrap())?;
135 stream
136 .ReadAsync(&buffer, buffer.Capacity()?, InputStreamOptions::None)?
137 .get()?;
138
139 let data_reader = DataReader::FromBuffer(&buffer)?;
140 let length = data_reader.UnconsumedBufferLength()?;
141 let mut bytes = vec![0u8; length as usize];
142 data_reader.ReadBytes(&mut bytes)?;
143
144 Ok(bytes)
145 }
146}
147
148#[derive(thiserror::Error, Debug)]
149pub enum VideoEncoderError {
150 #[error("Windows API Error: {0}")]
151 WindowsError(#[from] windows::core::Error),
152 #[error("Frame send error: {0}")]
153 FrameSendError(#[from] mpsc::SendError<Option<(VideoEncoderSource, TimeSpan)>>),
154 #[error("Audio send error: {0}")]
155 AudioSendError(#[from] mpsc::SendError<Option<(AudioEncoderSource, TimeSpan)>>),
156 #[error("Video is disabled")]
157 VideoDisabled,
158 #[error("Audio is disabled")]
159 AudioDisabled,
160 #[error("IO Error: {0}")]
161 IoError(#[from] std::io::Error),
162}
163
164unsafe impl Send for VideoEncoderError {}
165unsafe impl Sync for VideoEncoderError {}
166
167pub enum VideoEncoderSource {
169 DirectX(SendDirectX<IDirect3DSurface>),
170 Buffer((SendDirectX<*const u8>, usize)),
171}
172
173pub enum AudioEncoderSource {
175 Buffer((SendDirectX<*const u8>, usize)),
176}
177
178pub struct VideoSettingsBuilder {
180 sub_type: VideoSettingsSubType,
181 bitrate: u32,
182 width: u32,
183 height: u32,
184 frame_rate: u32,
185 pixel_aspect_ratio: (u32, u32),
186 disabled: bool,
187}
188
189impl VideoSettingsBuilder {
190 pub const fn new(width: u32, height: u32) -> Self {
191 Self {
192 bitrate: 15000000,
193 frame_rate: 60,
194 pixel_aspect_ratio: (1, 1),
195 sub_type: VideoSettingsSubType::HEVC,
196 width,
197 height,
198 disabled: false,
199 }
200 }
201
202 pub const fn sub_type(mut self, sub_type: VideoSettingsSubType) -> Self {
203 self.sub_type = sub_type;
204 self
205 }
206
207 pub const fn bitrate(mut self, bitrate: u32) -> Self {
208 self.bitrate = bitrate;
209 self
210 }
211
212 pub const fn width(mut self, width: u32) -> Self {
213 self.width = width;
214 self
215 }
216
217 pub const fn height(mut self, height: u32) -> Self {
218 self.height = height;
219 self
220 }
221
222 pub const fn frame_rate(mut self, frame_rate: u32) -> Self {
223 self.frame_rate = frame_rate;
224 self
225 }
226
227 pub const fn pixel_aspect_ratio(mut self, pixel_aspect_ratio: (u32, u32)) -> Self {
228 self.pixel_aspect_ratio = pixel_aspect_ratio;
229 self
230 }
231
232 pub const fn disabled(mut self, disabled: bool) -> Self {
233 self.disabled = disabled;
234 self
235 }
236
237 fn build(self) -> Result<(VideoEncodingProperties, bool), VideoEncoderError> {
238 let properties = VideoEncodingProperties::new()?;
239
240 properties.SetSubtype(&self.sub_type.to_hstring())?;
241 properties.SetBitrate(self.bitrate)?;
242 properties.SetWidth(self.width)?;
243 properties.SetHeight(self.height)?;
244 properties.FrameRate()?.SetNumerator(self.frame_rate)?;
245 properties.FrameRate()?.SetDenominator(1)?;
246 properties
247 .PixelAspectRatio()?
248 .SetNumerator(self.pixel_aspect_ratio.0)?;
249 properties
250 .PixelAspectRatio()?
251 .SetDenominator(self.pixel_aspect_ratio.1)?;
252
253 Ok((properties, self.disabled))
254 }
255}
256
257pub struct AudioSettingsBuilder {
259 bitrate: u32,
260 channel_count: u32,
261 sample_rate: u32,
262 bit_per_sample: u32,
263 sub_type: AudioSettingsSubType,
264 disabled: bool,
265}
266
267impl AudioSettingsBuilder {
268 pub const fn new() -> Self {
269 Self {
270 bitrate: 192000,
271 channel_count: 2,
272 sample_rate: 48000,
273 bit_per_sample: 16,
274 sub_type: AudioSettingsSubType::AAC,
275 disabled: false,
276 }
277 }
278 pub const fn bitrate(mut self, bitrate: u32) -> Self {
279 self.bitrate = bitrate;
280 self
281 }
282
283 pub const fn channel_count(mut self, channel_count: u32) -> Self {
284 self.channel_count = channel_count;
285 self
286 }
287
288 pub const fn sample_rate(mut self, sample_rate: u32) -> Self {
289 self.sample_rate = sample_rate;
290 self
291 }
292
293 pub const fn bit_per_sample(mut self, bit_per_sample: u32) -> Self {
294 self.bit_per_sample = bit_per_sample;
295 self
296 }
297
298 pub const fn sub_type(mut self, sub_type: AudioSettingsSubType) -> Self {
299 self.sub_type = sub_type;
300 self
301 }
302
303 pub const fn disabled(mut self, disabled: bool) -> Self {
304 self.disabled = disabled;
305 self
306 }
307
308 fn build(self) -> Result<(AudioEncodingProperties, bool), VideoEncoderError> {
309 let properties = AudioEncodingProperties::new()?;
310 properties.SetBitrate(self.bitrate)?;
311 properties.SetChannelCount(self.channel_count)?;
312 properties.SetSampleRate(self.sample_rate)?;
313 properties.SetBitsPerSample(self.bit_per_sample)?;
314 properties.SetSubtype(&self.sub_type.to_hstring())?;
315
316 Ok((properties, self.disabled))
317 }
318}
319
320impl Default for AudioSettingsBuilder {
321 fn default() -> Self {
322 Self::new()
323 }
324}
325
326pub struct ContainerSettingsBuilder {
328 sub_type: ContainerSettingsSubType,
329}
330
331impl ContainerSettingsBuilder {
332 pub const fn new() -> Self {
333 Self {
334 sub_type: ContainerSettingsSubType::MPEG4,
335 }
336 }
337
338 pub const fn sub_type(mut self, sub_type: ContainerSettingsSubType) -> Self {
339 self.sub_type = sub_type;
340 self
341 }
342
343 fn build(self) -> Result<ContainerEncodingProperties, VideoEncoderError> {
344 let properties = ContainerEncodingProperties::new()?;
345 properties.SetSubtype(&self.sub_type.to_hstring())?;
346 Ok(properties)
347 }
348}
349
350impl Default for ContainerSettingsBuilder {
351 fn default() -> Self {
352 Self::new()
353 }
354}
355
356#[derive(Eq, PartialEq, Clone, Copy, Debug)]
358pub enum VideoSettingsSubType {
359 ARGB32,
360 BGRA8,
361 D16,
362 H263,
363 H264,
364 H264ES,
365 HEVC,
366 HEVCES,
367 IYUV,
368 L8,
369 L16,
370 MJPG,
371 NV12,
372 MPEG1,
373 MPEG2,
374 RGB24,
375 RGB32,
376 WMV3,
377 WVC1,
378 VP9,
379 YUY2,
380 YV12,
381}
382
383impl VideoSettingsSubType {
384 pub fn to_hstring(&self) -> HSTRING {
385 let s = match self {
386 Self::ARGB32 => "ARGB32",
387 Self::BGRA8 => "BGRA8",
388 Self::D16 => "D16",
389 Self::H263 => "H263",
390 Self::H264 => "H264",
391 Self::H264ES => "H264ES",
392 Self::HEVC => "HEVC",
393 Self::HEVCES => "HEVCES",
394 Self::IYUV => "IYUV",
395 Self::L8 => "L8",
396 Self::L16 => "L16",
397 Self::MJPG => "MJPG",
398 Self::NV12 => "NV12",
399 Self::MPEG1 => "MPEG1",
400 Self::MPEG2 => "MPEG2",
401 Self::RGB24 => "RGB24",
402 Self::RGB32 => "RGB32",
403 Self::WMV3 => "WMV3",
404 Self::WVC1 => "WVC1",
405 Self::VP9 => "VP9",
406 Self::YUY2 => "YUY2",
407 Self::YV12 => "YV12",
408 };
409
410 HSTRING::from(s)
411 }
412}
413
414#[derive(Eq, PartialEq, Clone, Copy, Debug)]
416pub enum AudioSettingsSubType {
417 AAC,
418 AC3,
419 AACADTS,
420 AACHDCP,
421 AC3SPDIF,
422 AC3HDCP,
423 ADTS,
424 ALAC,
425 AMRNB,
426 AWRWB,
427 DTS,
428 EAC3,
429 FLAC,
430 Float,
431 MP3,
432 MPEG,
433 OPUS,
434 PCM,
435 WMA8,
436 WMA9,
437 Vorbis,
438}
439
440impl AudioSettingsSubType {
441 pub fn to_hstring(&self) -> HSTRING {
442 let s = match self {
443 Self::AAC => "AAC",
444 Self::AC3 => "AC3",
445 Self::AACADTS => "AACADTS",
446 Self::AACHDCP => "AACHDCP",
447 Self::AC3SPDIF => "AC3SPDIF",
448 Self::AC3HDCP => "AC3HDCP",
449 Self::ADTS => "ADTS",
450 Self::ALAC => "ALAC",
451 Self::AMRNB => "AMRNB",
452 Self::AWRWB => "AWRWB",
453 Self::DTS => "DTS",
454 Self::EAC3 => "EAC3",
455 Self::FLAC => "FLAC",
456 Self::Float => "Float",
457 Self::MP3 => "MP3",
458 Self::MPEG => "MPEG",
459 Self::OPUS => "OPUS",
460 Self::PCM => "PCM",
461 Self::WMA8 => "WMA8",
462 Self::WMA9 => "WMA9",
463 Self::Vorbis => "Vorbis",
464 };
465
466 HSTRING::from(s)
467 }
468}
469
470#[derive(Eq, PartialEq, Clone, Copy, Debug)]
472pub enum ContainerSettingsSubType {
473 ASF,
474 MP3,
475 MPEG4,
476 AVI,
477 MPEG2,
478 WAVE,
479 AACADTS,
480 ADTS,
481 GP3,
482 AMR,
483 FLAC,
484}
485
486impl ContainerSettingsSubType {
487 pub fn to_hstring(&self) -> HSTRING {
488 match self {
489 Self::ASF => HSTRING::from("ASF"),
490 Self::MP3 => HSTRING::from("MP3"),
491 Self::MPEG4 => HSTRING::from("MPEG4"),
492 Self::AVI => HSTRING::from("AVI"),
493 Self::MPEG2 => HSTRING::from("MPEG2"),
494 Self::WAVE => HSTRING::from("WAVE"),
495 Self::AACADTS => HSTRING::from("AACADTS"),
496 Self::ADTS => HSTRING::from("ADTS"),
497 Self::GP3 => HSTRING::from("3GP"),
498 Self::AMR => HSTRING::from("AMR"),
499 Self::FLAC => HSTRING::from("FLAC"),
500 }
501 }
502}
503
504pub struct VideoEncoder {
506 first_timespan: Option<TimeSpan>,
507 frame_sender: mpsc::Sender<Option<(VideoEncoderSource, TimeSpan)>>,
508 audio_sender: mpsc::Sender<Option<(AudioEncoderSource, TimeSpan)>>,
509 sample_requested: i64,
510 media_stream_source: MediaStreamSource,
511 starting: i64,
512 transcode_thread: Option<JoinHandle<Result<(), VideoEncoderError>>>,
513 frame_notify: Arc<(Mutex<bool>, Condvar)>,
514 audio_notify: Arc<(Mutex<bool>, Condvar)>,
515 error_notify: Arc<AtomicBool>,
516 is_video_disabled: bool,
517 is_audio_disabled: bool,
518}
519
520impl VideoEncoder {
521 #[inline]
536 pub fn new<P: AsRef<Path>>(
537 video_settings: VideoSettingsBuilder,
538 audio_settings: AudioSettingsBuilder,
539 container_settings: ContainerSettingsBuilder,
540 path: P,
541 ) -> Result<Self, VideoEncoderError> {
542 let path = path.as_ref();
543 let media_encoding_profile = MediaEncodingProfile::new()?;
544
545 let (video_encoding_properties, is_video_disabled) = video_settings.build()?;
546 media_encoding_profile.SetVideo(&video_encoding_properties)?;
547 let (audio_encoding_properties, is_audio_disabled) = audio_settings.build()?;
548 media_encoding_profile.SetAudio(&audio_encoding_properties)?;
549 let container_encoding_properties = container_settings.build()?;
550 media_encoding_profile.SetContainer(&container_encoding_properties)?;
551
552 let video_encoding_properties = VideoEncodingProperties::CreateUncompressed(
553 &MediaEncodingSubtypes::Bgra8()?,
554 video_encoding_properties.Width()?,
555 video_encoding_properties.Height()?,
556 )?;
557 let video_stream_descriptor = VideoStreamDescriptor::Create(&video_encoding_properties)?;
558
559 let audio_encoding_properties = AudioEncodingProperties::CreateAac(
560 audio_encoding_properties.SampleRate()?,
561 audio_encoding_properties.ChannelCount()?,
562 audio_encoding_properties.Bitrate()?,
563 )?;
564 let audio_stream_descriptor = AudioStreamDescriptor::Create(&audio_encoding_properties)?;
565
566 let media_stream_source = MediaStreamSource::CreateFromDescriptors(
567 &video_stream_descriptor,
568 &audio_stream_descriptor,
569 )?;
570 media_stream_source.SetBufferTime(TimeSpan::default())?;
571
572 let starting = media_stream_source.Starting(&TypedEventHandler::<
573 MediaStreamSource,
574 MediaStreamSourceStartingEventArgs,
575 >::new(move |_, stream_start| {
576 let stream_start = stream_start
577 .as_ref()
578 .expect("MediaStreamSource Starting parameter was None This Should Not Happen.");
579
580 stream_start
581 .Request()?
582 .SetActualStartPosition(TimeSpan { Duration: 0 })?;
583 Ok(())
584 }))?;
585
586 let (frame_sender, frame_receiver) =
587 mpsc::channel::<Option<(VideoEncoderSource, TimeSpan)>>();
588
589 let (audio_sender, audio_receiver) =
590 mpsc::channel::<Option<(AudioEncoderSource, TimeSpan)>>();
591
592 let frame_notify = Arc::new((Mutex::new(false), Condvar::new()));
593 let audio_notify = Arc::new((Mutex::new(false), Condvar::new()));
594
595 let sample_requested = media_stream_source.SampleRequested(&TypedEventHandler::<
596 MediaStreamSource,
597 MediaStreamSourceSampleRequestedEventArgs,
598 >::new({
599 let frame_receiver = frame_receiver;
600 let frame_notify = frame_notify.clone();
601
602 let audio_receiver = audio_receiver;
603 let audio_notify = audio_notify.clone();
604
605 move |_, sample_requested| {
606 let sample_requested = sample_requested.as_ref().expect(
607 "MediaStreamSource SampleRequested parameter was None This Should Not Happen.",
608 );
609
610 if sample_requested
611 .Request()?
612 .StreamDescriptor()?
613 .cast::<AudioStreamDescriptor>()
614 .is_ok()
615 {
616 if is_audio_disabled {
617 sample_requested.Request()?.SetSample(None)?;
618
619 return Ok(());
620 }
621
622 let audio = match audio_receiver.recv() {
623 Ok(audio) => audio,
624 Err(e) => panic!("Failed to receive audio from audio sender: {e}"),
625 };
626
627 match audio {
628 Some((source, timespan)) => {
629 let sample = match source {
630 AudioEncoderSource::Buffer(buffer_data) => {
631 let buffer = buffer_data.0;
632 let buffer =
633 unsafe { slice::from_raw_parts(buffer.0, buffer_data.1) };
634 let buffer = CryptographicBuffer::CreateFromByteArray(buffer)?;
635 MediaStreamSample::CreateFromBuffer(&buffer, timespan)?
636 }
637 };
638
639 sample_requested.Request()?.SetSample(&sample)?;
640 }
641 None => {
642 sample_requested.Request()?.SetSample(None)?;
643 }
644 }
645
646 let (lock, cvar) = &*audio_notify;
647 *lock.lock() = true;
648 cvar.notify_one();
649 } else {
650 if is_video_disabled {
651 sample_requested.Request()?.SetSample(None)?;
652
653 return Ok(());
654 }
655
656 let frame = match frame_receiver.recv() {
657 Ok(frame) => frame,
658 Err(e) => panic!("Failed to receive frame from frame sender: {e}"),
659 };
660
661 match frame {
662 Some((source, timespan)) => {
663 let sample = match source {
664 VideoEncoderSource::DirectX(surface) => {
665 MediaStreamSample::CreateFromDirect3D11Surface(
666 &surface.0, timespan,
667 )?
668 }
669 VideoEncoderSource::Buffer(buffer_data) => {
670 let buffer = buffer_data.0;
671 let buffer =
672 unsafe { slice::from_raw_parts(buffer.0, buffer_data.1) };
673 let buffer = CryptographicBuffer::CreateFromByteArray(buffer)?;
674 MediaStreamSample::CreateFromBuffer(&buffer, timespan)?
675 }
676 };
677
678 sample_requested.Request()?.SetSample(&sample)?;
679 }
680 None => {
681 sample_requested.Request()?.SetSample(None)?;
682 }
683 }
684
685 let (lock, cvar) = &*frame_notify;
686 *lock.lock() = true;
687 cvar.notify_one();
688 }
689
690 Ok(())
691 }
692 }))?;
693
694 let media_transcoder = MediaTranscoder::new()?;
695 media_transcoder.SetHardwareAccelerationEnabled(true)?;
696
697 File::create(path)?;
698 let path = fs::canonicalize(path).unwrap().to_string_lossy()[4..].to_string();
699 let path = Path::new(&path);
700
701 let path = &HSTRING::from(path.as_os_str().to_os_string());
702
703 let file = StorageFile::GetFileFromPathAsync(path)?.get()?;
704 let media_stream_output = file.OpenAsync(FileAccessMode::ReadWrite)?.get()?;
705
706 let transcode = media_transcoder
707 .PrepareMediaStreamSourceTranscodeAsync(
708 &media_stream_source,
709 &media_stream_output,
710 &media_encoding_profile,
711 )?
712 .get()?;
713
714 let error_notify = Arc::new(AtomicBool::new(false));
715 let transcode_thread = thread::spawn({
716 let error_notify = error_notify.clone();
717
718 move || -> Result<(), VideoEncoderError> {
719 let result = transcode.TranscodeAsync();
720
721 if result.is_err() {
722 error_notify.store(true, atomic::Ordering::Relaxed);
723 }
724
725 result?.get()?;
726
727 drop(media_transcoder);
728
729 Ok(())
730 }
731 });
732
733 Ok(Self {
734 first_timespan: None,
735 frame_sender,
736 audio_sender,
737 sample_requested,
738 media_stream_source,
739 starting,
740 transcode_thread: Some(transcode_thread),
741 frame_notify,
742 audio_notify,
743 error_notify,
744 is_video_disabled,
745 is_audio_disabled,
746 })
747 }
748
749 #[inline]
764 pub fn new_from_stream(
765 video_settings: VideoSettingsBuilder,
766 audio_settings: AudioSettingsBuilder,
767 container_settings: ContainerSettingsBuilder,
768 stream: IRandomAccessStream,
769 ) -> Result<Self, VideoEncoderError> {
770 let media_encoding_profile = MediaEncodingProfile::new()?;
771
772 let (video_encoding_properties, is_video_disabled) = video_settings.build()?;
773 media_encoding_profile.SetVideo(&video_encoding_properties)?;
774 let (audio_encoding_properties, is_audio_disabled) = audio_settings.build()?;
775 media_encoding_profile.SetAudio(&audio_encoding_properties)?;
776 let container_encoding_properties = container_settings.build()?;
777 media_encoding_profile.SetContainer(&container_encoding_properties)?;
778
779 let video_encoding_properties = VideoEncodingProperties::CreateUncompressed(
780 &MediaEncodingSubtypes::Bgra8()?,
781 video_encoding_properties.Width()?,
782 video_encoding_properties.Height()?,
783 )?;
784 let video_stream_descriptor = VideoStreamDescriptor::Create(&video_encoding_properties)?;
785
786 let audio_encoding_properties = AudioEncodingProperties::CreateAac(
787 audio_encoding_properties.SampleRate()?,
788 audio_encoding_properties.ChannelCount()?,
789 audio_encoding_properties.Bitrate()?,
790 )?;
791 let audio_stream_descriptor = AudioStreamDescriptor::Create(&audio_encoding_properties)?;
792
793 let media_stream_source = MediaStreamSource::CreateFromDescriptors(
794 &video_stream_descriptor,
795 &audio_stream_descriptor,
796 )?;
797 media_stream_source.SetBufferTime(TimeSpan::default())?;
798
799 let starting = media_stream_source.Starting(&TypedEventHandler::<
800 MediaStreamSource,
801 MediaStreamSourceStartingEventArgs,
802 >::new(move |_, stream_start| {
803 let stream_start = stream_start
804 .as_ref()
805 .expect("MediaStreamSource Starting parameter was None This Should Not Happen.");
806
807 stream_start
808 .Request()?
809 .SetActualStartPosition(TimeSpan { Duration: 0 })?;
810 Ok(())
811 }))?;
812
813 let (frame_sender, frame_receiver) =
814 mpsc::channel::<Option<(VideoEncoderSource, TimeSpan)>>();
815
816 let (audio_sender, audio_receiver) =
817 mpsc::channel::<Option<(AudioEncoderSource, TimeSpan)>>();
818
819 let frame_notify = Arc::new((Mutex::new(false), Condvar::new()));
820 let audio_notify = Arc::new((Mutex::new(false), Condvar::new()));
821
822 let sample_requested = media_stream_source.SampleRequested(&TypedEventHandler::<
823 MediaStreamSource,
824 MediaStreamSourceSampleRequestedEventArgs,
825 >::new({
826 let frame_receiver = frame_receiver;
827 let frame_notify = frame_notify.clone();
828
829 let audio_receiver = audio_receiver;
830 let audio_notify = audio_notify.clone();
831
832 move |_, sample_requested| {
833 let sample_requested = sample_requested.as_ref().expect(
834 "MediaStreamSource SampleRequested parameter was None This Should Not Happen.",
835 );
836
837 if sample_requested
838 .Request()?
839 .StreamDescriptor()?
840 .cast::<AudioStreamDescriptor>()
841 .is_ok()
842 {
843 if is_audio_disabled {
844 sample_requested.Request()?.SetSample(None)?;
845
846 return Ok(());
847 }
848
849 let audio = match audio_receiver.recv() {
850 Ok(audio) => audio,
851 Err(e) => panic!("Failed to receive audio from audio sender: {e}"),
852 };
853
854 match audio {
855 Some((source, timespan)) => {
856 let sample = match source {
857 AudioEncoderSource::Buffer(buffer_data) => {
858 let buffer = buffer_data.0;
859 let buffer =
860 unsafe { slice::from_raw_parts(buffer.0, buffer_data.1) };
861 let buffer = CryptographicBuffer::CreateFromByteArray(buffer)?;
862 MediaStreamSample::CreateFromBuffer(&buffer, timespan)?
863 }
864 };
865
866 sample_requested.Request()?.SetSample(&sample)?;
867 }
868 None => {
869 sample_requested.Request()?.SetSample(None)?;
870 }
871 }
872
873 let (lock, cvar) = &*audio_notify;
874 *lock.lock() = true;
875 cvar.notify_one();
876 } else {
877 if is_video_disabled {
878 sample_requested.Request()?.SetSample(None)?;
879
880 return Ok(());
881 }
882
883 let frame = match frame_receiver.recv() {
884 Ok(frame) => frame,
885 Err(e) => panic!("Failed to receive frame from frame sender: {e}"),
886 };
887
888 match frame {
889 Some((source, timespan)) => {
890 let sample = match source {
891 VideoEncoderSource::DirectX(surface) => {
892 MediaStreamSample::CreateFromDirect3D11Surface(
893 &surface.0, timespan,
894 )?
895 }
896 VideoEncoderSource::Buffer(buffer_data) => {
897 let buffer = buffer_data.0;
898 let buffer =
899 unsafe { slice::from_raw_parts(buffer.0, buffer_data.1) };
900 let buffer = CryptographicBuffer::CreateFromByteArray(buffer)?;
901 MediaStreamSample::CreateFromBuffer(&buffer, timespan)?
902 }
903 };
904
905 sample_requested.Request()?.SetSample(&sample)?;
906 }
907 None => {
908 sample_requested.Request()?.SetSample(None)?;
909 }
910 }
911
912 let (lock, cvar) = &*frame_notify;
913 *lock.lock() = true;
914 cvar.notify_one();
915 }
916
917 Ok(())
918 }
919 }))?;
920
921 let media_transcoder = MediaTranscoder::new()?;
922 media_transcoder.SetHardwareAccelerationEnabled(true)?;
923
924 let transcode = media_transcoder
925 .PrepareMediaStreamSourceTranscodeAsync(
926 &media_stream_source,
927 &stream,
928 &media_encoding_profile,
929 )?
930 .get()?;
931
932 let error_notify = Arc::new(AtomicBool::new(false));
933 let transcode_thread = thread::spawn({
934 let error_notify = error_notify.clone();
935
936 move || -> Result<(), VideoEncoderError> {
937 let result = transcode.TranscodeAsync();
938
939 if result.is_err() {
940 error_notify.store(true, atomic::Ordering::Relaxed);
941 }
942
943 result?.get()?;
944
945 drop(media_transcoder);
946
947 Ok(())
948 }
949 });
950
951 Ok(Self {
952 first_timespan: None,
953 frame_sender,
954 audio_sender,
955 sample_requested,
956 media_stream_source,
957 starting,
958 transcode_thread: Some(transcode_thread),
959 frame_notify,
960 audio_notify,
961 error_notify,
962 is_video_disabled,
963 is_audio_disabled,
964 })
965 }
966
967 #[inline]
978 pub fn send_frame(&mut self, frame: &mut Frame) -> Result<(), VideoEncoderError> {
979 if self.is_video_disabled {
980 return Err(VideoEncoderError::VideoDisabled);
981 }
982
983 let timespan = match self.first_timespan {
984 Some(timespan) => TimeSpan {
985 Duration: frame.timespan().Duration - timespan.Duration,
986 },
987 None => {
988 let timespan = frame.timespan();
989 self.first_timespan = Some(timespan);
990 TimeSpan { Duration: 0 }
991 }
992 };
993
994 self.frame_sender.send(Some((
995 VideoEncoderSource::DirectX(SendDirectX::new(unsafe {
996 frame.as_raw_surface().clone()
997 })),
998 timespan,
999 )))?;
1000
1001 let (lock, cvar) = &*self.frame_notify;
1002 let mut processed = lock.lock();
1003 if !*processed {
1004 cvar.wait(&mut processed);
1005 }
1006 *processed = false;
1007 drop(processed);
1008
1009 if self.error_notify.load(atomic::Ordering::Relaxed) {
1010 if let Some(transcode_thread) = self.transcode_thread.take() {
1011 transcode_thread
1012 .join()
1013 .expect("Failed to join transcode thread")?;
1014 }
1015 }
1016
1017 Ok(())
1018 }
1019
1020 #[inline]
1032 pub fn send_frame_with_audio(
1033 &mut self,
1034 frame: &mut Frame,
1035 audio_buffer: &[u8],
1036 ) -> Result<(), VideoEncoderError> {
1037 if self.is_video_disabled {
1038 return Err(VideoEncoderError::VideoDisabled);
1039 }
1040
1041 if self.is_audio_disabled {
1042 return Err(VideoEncoderError::AudioDisabled);
1043 }
1044
1045 let timespan = match self.first_timespan {
1046 Some(timespan) => TimeSpan {
1047 Duration: frame.timespan().Duration - timespan.Duration,
1048 },
1049 None => {
1050 let timespan = frame.timespan();
1051 self.first_timespan = Some(timespan);
1052 TimeSpan { Duration: 0 }
1053 }
1054 };
1055
1056 self.frame_sender.send(Some((
1057 VideoEncoderSource::DirectX(SendDirectX::new(unsafe {
1058 frame.as_raw_surface().clone()
1059 })),
1060 timespan,
1061 )))?;
1062
1063 let (lock, cvar) = &*self.frame_notify;
1064 let mut processed = lock.lock();
1065 if !*processed {
1066 cvar.wait(&mut processed);
1067 }
1068 *processed = false;
1069 drop(processed);
1070
1071 if self.error_notify.load(atomic::Ordering::Relaxed) {
1072 if let Some(transcode_thread) = self.transcode_thread.take() {
1073 transcode_thread
1074 .join()
1075 .expect("Failed to join transcode thread")?;
1076 }
1077 }
1078
1079 self.audio_sender.send(Some((
1080 AudioEncoderSource::Buffer((
1081 SendDirectX::new(audio_buffer.as_ptr()),
1082 audio_buffer.len(),
1083 )),
1084 timespan,
1085 )))?;
1086
1087 let (lock, cvar) = &*self.audio_notify;
1088 let mut processed = lock.lock();
1089 if !*processed {
1090 cvar.wait(&mut processed);
1091 }
1092 *processed = false;
1093 drop(processed);
1094
1095 if self.error_notify.load(atomic::Ordering::Relaxed) {
1096 if let Some(transcode_thread) = self.transcode_thread.take() {
1097 transcode_thread
1098 .join()
1099 .expect("Failed to join transcode thread")?;
1100 }
1101 }
1102
1103 Ok(())
1104 }
1105
1106 #[inline]
1118 pub fn send_frame_buffer(
1119 &mut self,
1120 buffer: &[u8],
1121 timespan: i64,
1122 ) -> Result<(), VideoEncoderError> {
1123 if self.is_video_disabled {
1124 return Err(VideoEncoderError::VideoDisabled);
1125 }
1126
1127 let frame_timespan = timespan;
1128 let timespan = match self.first_timespan {
1129 Some(timespan) => TimeSpan {
1130 Duration: frame_timespan - timespan.Duration,
1131 },
1132 None => {
1133 let timespan = frame_timespan;
1134 self.first_timespan = Some(TimeSpan { Duration: timespan });
1135 TimeSpan { Duration: 0 }
1136 }
1137 };
1138
1139 self.frame_sender.send(Some((
1140 VideoEncoderSource::Buffer((SendDirectX::new(buffer.as_ptr()), buffer.len())),
1141 timespan,
1142 )))?;
1143
1144 let (lock, cvar) = &*self.frame_notify;
1145 let mut processed = lock.lock();
1146 if !*processed {
1147 cvar.wait(&mut processed);
1148 }
1149 *processed = false;
1150 drop(processed);
1151
1152 if self.error_notify.load(atomic::Ordering::Relaxed) {
1153 if let Some(transcode_thread) = self.transcode_thread.take() {
1154 transcode_thread
1155 .join()
1156 .expect("Failed to join transcode thread")?;
1157 }
1158 }
1159
1160 Ok(())
1161 }
1162
1163 #[inline]
1175 pub fn send_audio_buffer(
1176 &mut self,
1177 buffer: &[u8],
1178 timespan: i64,
1179 ) -> Result<(), VideoEncoderError> {
1180 if self.is_audio_disabled {
1181 return Err(VideoEncoderError::AudioDisabled);
1182 }
1183
1184 let audio_timespan = timespan;
1185 let timespan = match self.first_timespan {
1186 Some(timespan) => TimeSpan {
1187 Duration: audio_timespan - timespan.Duration,
1188 },
1189 None => {
1190 let timespan = audio_timespan;
1191 self.first_timespan = Some(TimeSpan { Duration: timespan });
1192 TimeSpan { Duration: 0 }
1193 }
1194 };
1195
1196 self.audio_sender.send(Some((
1197 AudioEncoderSource::Buffer((SendDirectX::new(buffer.as_ptr()), buffer.len())),
1198 timespan,
1199 )))?;
1200
1201 let (lock, cvar) = &*self.audio_notify;
1202 let mut processed = lock.lock();
1203 if !*processed {
1204 cvar.wait(&mut processed);
1205 }
1206 *processed = false;
1207 drop(processed);
1208
1209 if self.error_notify.load(atomic::Ordering::Relaxed) {
1210 if let Some(transcode_thread) = self.transcode_thread.take() {
1211 transcode_thread
1212 .join()
1213 .expect("Failed to join transcode thread")?;
1214 }
1215 }
1216
1217 Ok(())
1218 }
1219
1220 #[inline]
1227 pub fn finish(mut self) -> Result<(), VideoEncoderError> {
1228 self.frame_sender.send(None)?;
1229 self.audio_sender.send(None)?;
1230
1231 if let Some(transcode_thread) = self.transcode_thread.take() {
1232 transcode_thread
1233 .join()
1234 .expect("Failed to join transcode thread")?;
1235 }
1236
1237 self.media_stream_source.RemoveStarting(self.starting)?;
1238 self.media_stream_source
1239 .RemoveSampleRequested(self.sample_requested)?;
1240
1241 Ok(())
1242 }
1243}
1244
1245impl Drop for VideoEncoder {
1246 #[inline]
1247 fn drop(&mut self) {
1248 let _ = self.frame_sender.send(None);
1249
1250 if let Some(transcode_thread) = self.transcode_thread.take() {
1251 let _ = transcode_thread.join();
1252 }
1253 }
1254}
1255
1256#[allow(clippy::non_send_fields_in_send_ty)]
1257unsafe impl Send for VideoEncoder {}