/// <summary> /// Video resolution changed event handler. /// </summary> /// <param name="width">The new video frame width.</param> /// <param name="height">The new video frame height.</param> /// <param name="stride">The new video frame stride.</param> private static void OnVideoResolutionChanged(uint width, uint height, uint stride) { try { if (_vpxEncoder == null || (_vpxEncoder.GetWidth() != width || _vpxEncoder.GetHeight() != height || _vpxEncoder.GetStride() != stride)) { //_vpxEncoderReady = false; if (_vpxEncoder != null) { _vpxEncoder.Dispose(); } _vpxEncoder = new VpxEncoder(); _vpxEncoder.InitEncoder(width, height, stride); logger.LogInformation($"VPX encoder initialised with width {width}, height {height} and stride {stride}."); //_vpxEncoderReady = true; } } catch (Exception excp) { logger.LogWarning("Exception OnVideoResolutionChangedEvent. " + excp.Message); } }
/// <summary> /// Starts the Media Foundation sampling. /// </summary> unsafe private void SampleMp4Media() { try { logger.LogDebug("Starting mp4 media sampling thread."); _isMp4Sampling = true; VpxEncoder vpxEncoder = null; uint vp8Timestamp = 0; uint mulawTimestamp = 0; while (!_exit) { if (OnMp4MediaSampleReady == null) { logger.LogDebug("No active clients, media sampling paused."); break; } else { byte[] sampleBuffer = null; var sample = _mediaSource.GetSample(ref sampleBuffer); if (sample != null && sample.HasVideoSample) { if (vpxEncoder == null || (vpxEncoder.GetWidth() != sample.Width || vpxEncoder.GetHeight() != sample.Height || vpxEncoder.GetStride() != sample.Stride)) { if (vpxEncoder != null) { vpxEncoder.Dispose(); } vpxEncoder = InitialiseVpxEncoder((uint)sample.Width, (uint)sample.Height, (uint)sample.Stride); } byte[] vpxEncodedBuffer = null; unsafe { fixed(byte *p = sampleBuffer) { int encodeResult = vpxEncoder.Encode(p, sampleBuffer.Length, 1, ref vpxEncodedBuffer); if (encodeResult != 0) { logger.LogWarning("VPX encode of video sample failed."); } } } OnMp4MediaSampleReady?.Invoke(SDPMediaTypesEnum.video, vp8Timestamp, vpxEncodedBuffer); //Console.WriteLine($"Video SeqNum {videoSeqNum}, timestamp {videoTimestamp}, buffer length {vpxEncodedBuffer.Length}, frame count {sampleProps.FrameCount}."); vp8Timestamp += VP8_TIMESTAMP_SPACING; } else if (sample != null && sample.HasAudioSample) { uint sampleDuration = (uint)(sampleBuffer.Length / 2); byte[] mulawSample = new byte[sampleDuration]; int sampleIndex = 0; for (int index = 0; index < sampleBuffer.Length; index += 2) { var ulawByte = MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(sampleBuffer, index)); mulawSample[sampleIndex++] = ulawByte; } OnMp4MediaSampleReady?.Invoke(SDPMediaTypesEnum.audio, mulawTimestamp, mulawSample); //Console.WriteLine($"Audio SeqNum {audioSeqNum}, timestamp {audioTimestamp}, buffer length {mulawSample.Length}."); mulawTimestamp += sampleDuration; } } } vpxEncoder.Dispose(); } catch (Exception excp) { logger.LogWarning("Exception SampleMp4Media. " + excp.Message); } finally { logger.LogDebug("mp4 sampling thread stopped."); _isMp4Sampling = false; } }