/// <summary> /// Renders the specified media block. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { // We don't need to render anything while we are seeking. Simply drop the blocks. if (MediaElement.IsSeeking) { return; } if (AudioBuffer == null) { return; } // Capture Media Block Reference var block = mediaBlock as AudioBlock; if (block == null) { return; } var audioBlocks = MediaCore.Blocks[MediaType.Audio]; var audioBlock = mediaBlock as AudioBlock; while (audioBlock != null) { // Write the block if we have to, avoiding repeated blocks. if (AudioBuffer.WriteTag < audioBlock.StartTime) { MediaElement.RaiseRenderingAudioEvent(audioBlock, clockPosition); AudioBuffer.Write(audioBlock.Buffer, audioBlock.BufferLength, audioBlock.StartTime, true); } // Stop adding if we have too much in there. if (AudioBuffer.CapacityPercent >= 0.8) { break; } // Retrieve the following block audioBlock = audioBlocks.Next(audioBlock) as AudioBlock; } }
/// <summary> /// Retrieves the block following the provided current block /// </summary> /// <param name="current">The current block.</param> /// <returns>The next media block</returns> public MediaBlock Next(MediaBlock current) { using (Locker.AcquireReaderLock()) { var currentIndex = current == null && PlaybackBlocks.Count > 0 ? 0 : PlaybackBlocks.IndexOf(current); if (currentIndex < 0) { return(null); } if (currentIndex + 1 < PlaybackBlocks.Count) { return(PlaybackBlocks[currentIndex + 1]); } return(null); } }
private static void PrintFrameInfo(MediaBlock e) { { var a = e as AudioBlock; if (a != null) { $"{e.MediaType,-10} | PTS: {e.StartTime.TotalSeconds,8:0.00000} | DUR: {e.Duration.TotalSeconds,8:0.00000} | END: {e.EndTime.TotalSeconds,8:0.00000} | SMP: {a.SamplesPerChannel,6}".Trace(typeof(Program)); return; } } { var v = e as VideoBlock; if (v != null) { $"{e.MediaType,-10} | PTS: {e.StartTime.TotalSeconds,8:0.00000} | DUR: {e.Duration.TotalSeconds,8:0.00000} | END: {e.EndTime.TotalSeconds,8:0.00000} | DIM: {v.PixelWidth}x{v.PixelHeight}".Info(typeof(Program)); return; } } }
private int SendBlockToRenderer(MediaBlock currentBlock, TimeSpan playbackPosition) { // No blocks were rendered if (currentBlock == null || currentBlock.IsDisposed) { return(0); } var t = currentBlock.MediaType; var isAttachedPicture = t == MediaType.Video && Container.Components[t].StreamInfo.IsAttachedPictureDisposition; var lastBlockStartTime = MediaCore.LastRenderTime[t]; var isRepeatedBlock = lastBlockStartTime != TimeSpan.MinValue && lastBlockStartTime == currentBlock.StartTime; var requiresRepeatedBlocks = t == MediaType.Audio || isAttachedPicture; // For live streams, we don't want to display previosu blocks if (t == MediaType.Video && !isRepeatedBlock && !isAttachedPicture && Container.IsLiveStream) { isRepeatedBlock = lastBlockStartTime.Ticks >= currentBlock.StartTime.Ticks; } // Render by forced signal (TimeSpan.MinValue) or because simply it is time to do so // otherwise simply skip block rendering as we have sent the block already. if (isRepeatedBlock && !requiresRepeatedBlocks) { return(0); } // Process property changes coming from video blocks State.UpdateDynamicBlockProperties(currentBlock); // Capture the last render time so we don't repeat the block MediaCore.LastRenderTime[t] = currentBlock.StartTime; // Send the block to its corresponding renderer MediaCore.Renderers[t]?.Render(currentBlock, playbackPosition); // Log the block statistics for debugging LogRenderBlock(currentBlock, playbackPosition); return(1); }
private int SendBlockToRenderer(MediaBlock block, TimeSpan clockPosition) { // No blocks were rendered if (block == null) { return(0); } // Process property changes coming from video blocks State.UpdateDynamicBlockProperties(block, MediaCore.Blocks[block.MediaType]); // Send the block to its corresponding renderer MediaCore.Renderers[block.MediaType]?.Render(block, clockPosition); MediaCore.LastRenderTime[block.MediaType] = block.StartTime; // Log the block statistics for debugging LogRenderBlock(block, clockPosition, block.Index); // At this point, we are certain that a blocl has been // sent to its corresponding renderer. return(1); }
/// <summary> /// Renders the specified media block. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> /// <param name="renderIndex">Index of the render.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition, int renderIndex) { SpeedRatio = MediaElement?.Clock?.SpeedRatio ?? 0d; if (AudioBuffer == null) { return; } var block = mediaBlock as AudioBlock; if (block == null) { return; } var currentIndex = renderIndex; var audioBlocks = MediaElement.Blocks[MediaType.Audio]; var addedBlockCount = 0; var addedBytes = 0; while (currentIndex >= 0 && currentIndex < audioBlocks.Count) { var audioBlock = audioBlocks[currentIndex] as AudioBlock; if (AudioBuffer.WriteTag < audioBlock.StartTime) { AudioBuffer.Write(audioBlock.Buffer, audioBlock.BufferLength, audioBlock.StartTime, true); addedBlockCount++; addedBytes += audioBlock.BufferLength; } currentIndex++; // Stop adding if we have too much in there. if (AudioBuffer.CapacityPercent >= 0.8) { break; } } }
/// <summary> /// Renders the specified media block. /// This needs to return immediately so the calling thread is not disturbed. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { var block = mediaBlock as VideoBlock; if (block == null) { return; } if (IsRenderingInProgress.Value == true) { MediaElement?.MediaCore?.Log(MediaLogMessageType.Debug, $"{nameof(VideoRenderer)}: Frame skipped at {mediaBlock.StartTime}"); return; } // Flag the start of a rendering cycle IsRenderingInProgress.Value = true; // Ensure the target bitmap can be loaded GuiContext.Current.EnqueueInvoke(DispatcherPriority.Render, () => { try { MediaElement.CaptionsView.RenderPacket(block, MediaCore); var bitmapData = LockTargetBitmap(block); if (bitmapData != null) { LoadTargetBitmapBuffer(bitmapData, block); MediaElement.RaiseRenderingVideoEvent(block, bitmapData, clockPosition); RenderTargetBitmap(block, bitmapData, clockPosition); } } catch { /* swallow */ } finally { IsRenderingInProgress.Value = false; } }); }
public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { var block = mediaBlock as VideoBlock; if (block == null) { return; } //if (IsRenderingInProgress.Value == true) //{ // //MediaElement.Logger.Log(MediaLogMessageType.Debug, $"{nameof(VideoRenderer)}: Frame skipped at {mediaBlock.StartTime}"); // return; //} IsRenderingInProgress.Value = true; var size = block.BufferLength; var bytes = new byte[size]; Marshal.Copy(block.Buffer, bytes, 0, size); Transform(block.Buffer, bytes, block.PixelWidth, block.PixelHeight); }
/// <summary> /// Logs a block rendering operation as a Trace Message /// if the debugger is attached. /// </summary> /// <param name="container">The container.</param> /// <param name="block">The block.</param> /// <param name="clockPosition">The clock position.</param> /// <param name="renderIndex">Index of the render.</param> internal static void LogRenderBlock(this MediaContainer container, MediaBlock block, TimeSpan clockPosition, int renderIndex) { if (Debugger.IsAttached == false) { return; } try { var drift = TimeSpan.FromTicks(clockPosition.Ticks - block.StartTime.Ticks); container?.Log(MediaLogMessageType.Trace, ($"{block.MediaType.ToString().Substring(0, 1)} " + $"BLK: {block.StartTime.Debug()} | " + $"CLK: {clockPosition.Debug()} | " + $"DFT: {drift.TotalMilliseconds,4:0} | " + $"IX: {renderIndex,3} | " + $"PQ: {container?.Components[block.MediaType]?.PacketBufferLength / 1024d,7:0.0}k | " + $"TQ: {container?.Components.PacketBufferLength / 1024d,7:0.0}k")); } catch { // swallow } }
public override void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { var block = BeginRenderingCycle(mediaBlock); if (block == null) { return; } IDisposable blockLock = null; try { if (!block.TryAcquireReaderLock(out blockLock)) { return; } var bitmap = Graphics.Write(block); if (bitmap == null) { return; } MediaElement?.RaiseRenderingVideoEvent(block, bitmap, clockPosition); UpdateTargetImage(DispatcherPriority.Loaded, true); } catch (Exception ex) { this.LogError(Aspects.VideoRenderer, $"{nameof(InteropVideoRenderer)}.{nameof(Render)} bitmap failed.", ex); } finally { blockLock?.Dispose(); FinishRenderingCycle(block, clockPosition); } }
/// <summary> /// Logs a block rendering operation as a Trace Message /// if the debugger is attached. /// </summary> /// <param name="mediaCore">The media engine.</param> /// <param name="block">The block.</param> /// <param name="clockPosition">The clock position.</param> /// <param name="renderIndex">Index of the render.</param> internal static void LogRenderBlock(this MediaEngine mediaCore, MediaBlock block, TimeSpan clockPosition, int renderIndex) { if (MediaEngine.Platform.IsInDebugMode == false) { return; } try { var drift = TimeSpan.FromTicks(clockPosition.Ticks - block.StartTime.Ticks); mediaCore?.Log(MediaLogMessageType.Trace, $"{block.MediaType.ToString().Substring(0, 1)} " + $"BLK: {block.StartTime.Format()} | " + $"CLK: {clockPosition.Format()} | " + $"DFT: {drift.TotalMilliseconds,4:0} | " + $"IX: {renderIndex,3} | " + $"PQ: {mediaCore.Container?.Components[block.MediaType]?.BufferLength / 1024d,7:0.0}k | " + $"TQ: {mediaCore.Container?.Components.BufferLength / 1024d,7:0.0}k"); } catch { // swallow } }
/// <summary> /// Renders the specified media block. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { lock (SyncLock) { var subtitleBlock = mediaBlock as SubtitleBlock; if (subtitleBlock == null) { return; } // Save the start and end times. We will need // them in order to make the subtitles disappear StartTime = subtitleBlock.StartTime; EndTime = subtitleBlock.EndTime; // Raise the subtitles event and keep track of the text. BlockText = MediaElement.RaiseRenderingSubtitlesEvent(subtitleBlock, clockPosition) ? string.Empty : string.Join("\r\n", subtitleBlock.Text); // Call the selective update method Update(clockPosition); } }
/// <inheritdoc /> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { lock (SyncLock) { if (mediaBlock is SubtitleBlock == false) { return; } // Get a reference to the subtitle block var subtitleBlock = (SubtitleBlock)mediaBlock; // Raise the subtitles event and keep track of the text. var cancelRender = MediaElement.RaiseRenderingSubtitlesEvent(subtitleBlock, clockPosition); if (cancelRender) { BlockText = string.Empty; StartTime = null; EndTime = null; } else { // Save the block text lines to display BlockText = string.Join("\r\n", subtitleBlock.Text); // Save the start and end times. We will need // them in order to make the subtitles disappear StartTime = subtitleBlock.StartTime; EndTime = subtitleBlock.EndTime; } // Call the selective update method Update(clockPosition); } }
/// <inheritdoc /> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { // We don't need to render anything while we are seeking. Simply drop the blocks. if (MediaCore.State.IsSeeking || HasFiredAudioDeviceStopped) { return; } var lockTaken = false; Monitor.TryEnter(SyncLock, SyncLockTimeout, ref lockTaken); if (lockTaken == false) { return; } try { if ((AudioDevice?.IsRunning ?? false) == false) { if (HasFiredAudioDeviceStopped) { return; } MediaElement.RaiseAudioDeviceStoppedEvent(); HasFiredAudioDeviceStopped = true; return; } if (AudioBuffer == null) { return; } // Capture Media Block Reference if (mediaBlock is AudioBlock == false) { return; } var audioBlock = (AudioBlock)mediaBlock; var audioBlocks = MediaCore.Blocks[MediaType.Audio]; while (audioBlock != null) { if (audioBlock.TryAcquireReaderLock(out var readLock) == false) { return; } using (readLock) { // Write the block if we have to, avoiding repeated blocks. if (AudioBuffer.WriteTag < audioBlock.StartTime) { AudioBuffer.Write(audioBlock.Buffer, audioBlock.SamplesBufferLength, audioBlock.StartTime, true); } // Stop adding if we have too much in there. if (AudioBuffer.CapacityPercent >= 0.5) { break; } // Retrieve the following block audioBlock = audioBlocks.ContinuousNext(audioBlock) as AudioBlock; } } } catch (Exception ex) { this.LogError(Aspects.AudioRenderer, $"{nameof(AudioRenderer)}.{nameof(Read)} has faulted.", ex); } finally { Monitor.Exit(SyncLock); } }
/// <summary> /// Renders the specified media block. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> /// <param name="renderIndex">Index of the render.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition, int renderIndex) { //placeholder }
/// <summary> /// Renders the specified media block. /// This needs to return immediately so the calling thread is not disturbed. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { var block = mediaBlock as VideoBlock; if (block == null) { return; } if (IsRenderingInProgress) { return; } IsRenderingInProgress = true; Utils.UIEnqueueInvoke( DispatcherPriority.Render, new Action <VideoBlock, TimeSpan>((b, cP) => { try { if (TargetBitmap == null || TargetBitmap.PixelWidth != b.PixelWidth || TargetBitmap.PixelHeight != b.PixelHeight) { InitializeTargetBitmap(b); } var updateRect = new Int32Rect(0, 0, b.PixelWidth, b.PixelHeight); TargetBitmap.WritePixels(updateRect, b.Buffer, b.BufferLength, b.BufferStride); MediaElement.RaiseRenderingVideoEvent(TargetBitmap, MediaElement.Container.MediaInfo.Streams[b.StreamIndex], b.StartTime, b.Duration, cP); var scaleTransform = MediaElement.ViewBox.LayoutTransform as ScaleTransform; // Process Aspect Ratio according to block. if (b.AspectWidth != b.AspectHeight) { var scaleX = b.AspectWidth > b.AspectHeight ? (double)b.AspectWidth / b.AspectHeight : 1d; var scaleY = b.AspectHeight > b.AspectWidth ? (double)b.AspectHeight / b.AspectWidth : 1d; if (scaleTransform == null) { scaleTransform = new ScaleTransform(scaleX, scaleY); MediaElement.ViewBox.LayoutTransform = scaleTransform; } if (scaleTransform.ScaleX != scaleX || scaleTransform.ScaleY != scaleY) { scaleTransform.ScaleX = scaleX; scaleTransform.ScaleY = scaleY; } } else { if (scaleTransform != null && (scaleTransform.ScaleX != 1d || scaleTransform.ScaleY != 1d)) { scaleTransform.ScaleX = 1d; scaleTransform.ScaleY = 1d; } } } catch (Exception ex) { Utils.Log(MediaElement, MediaLogMessageType.Error, $"{nameof(VideoRenderer)} {ex.GetType()}: {ex.Message}. Stack Trace:\r\n{ex.StackTrace}"); } finally { IsRenderingInProgress = false; } }), block, clockPosition); }
/// <summary> /// Renders the specified media block. /// This needs to return immediately so the calling thread is not disturbed. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { var block = mediaBlock as VideoBlock; if (block == null) { return; } if (IsRenderingInProgress.Value == true) { MediaElement.Logger.Log(MediaLogMessageType.Debug, $"{nameof(VideoRenderer)}: Frame skipped at {mediaBlock.StartTime}"); return; } IsRenderingInProgress.Value = true; Runner.UIEnqueueInvoke( DispatcherPriority.Render, new Action <VideoBlock, TimeSpan>((b, cP) => { try { // Skip rendering if Scrubbing is not enabled if (MediaElement.ScrubbingEnabled == false && MediaElement.IsPlaying == false) { return; } if (TargetBitmap == null || TargetBitmap.PixelWidth != b.PixelWidth || TargetBitmap.PixelHeight != b.PixelHeight) { InitializeTargetBitmap(b); } var updateRect = new Int32Rect(0, 0, b.PixelWidth, b.PixelHeight); TargetBitmap.WritePixels(updateRect, b.Buffer, b.BufferLength, b.BufferStride); MediaElement.VideoSmtpeTimecode = b.SmtpeTimecode; MediaElement.VideoHardwareDecoder = (MediaElement.Container?.Components?.Video?.IsUsingHardwareDecoding ?? false) ? MediaElement.Container?.Components?.Video?.HardwareAccelerator?.Name ?? string.Empty : string.Empty; MediaElement.RaiseRenderingVideoEvent( TargetBitmap, MediaElement.Container.MediaInfo.Streams[b.StreamIndex], b.SmtpeTimecode, b.DisplayPictureNumber, b.StartTime, b.Duration, cP); ApplyScaleTransform(b); } catch (Exception ex) { Utils.Log(MediaElement, MediaLogMessageType.Error, $"{nameof(VideoRenderer)} {ex.GetType()}: {ex.Message}. Stack Trace:\r\n{ex.StackTrace}"); } finally { IsRenderingInProgress.Value = false; } }), block, clockPosition); }
/// <summary> /// Renders the specified media block. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { // We don't need to render anything while we are seeking. Simply drop the blocks. if (MediaCore.State.IsSeeking) { return; } var lockTaken = false; Monitor.TryEnter(SyncLock, SyncLockTimeout, ref lockTaken); if (lockTaken == false) { return; } try { if ((AudioDevice?.IsRunning ?? false) == false) { // TODO: Handle this? -- see issue #93 return; } if (AudioBuffer == null) { return; } // Capture Media Block Reference if (mediaBlock is AudioBlock == false) { return; } var audioBlock = mediaBlock as AudioBlock; if (audioBlock == null) { return; } var audioBlocks = MediaCore.Blocks[MediaType.Audio]; while (audioBlock != null) { if (audioBlock.TryAcquireReaderLock(out var readLock) == false) { return; } using (readLock) { // Write the block if we have to, avoiding repeated blocks. if (AudioBuffer.WriteTag < audioBlock.StartTime) { MediaElement.RaiseRenderingAudioEvent(audioBlock, clockPosition); AudioBuffer.Write(audioBlock.Buffer, audioBlock.SamplesBufferLength, audioBlock.StartTime, true); } // Stop adding if we have too much in there. if (AudioBuffer.CapacityPercent >= 0.8) { break; } // Retrieve the following block audioBlock = audioBlocks.Next(audioBlock) as AudioBlock; } } } catch (Exception ex) { MediaCore?.Log(MediaLogMessageType.Error, $"{ex.GetType()} in {nameof(AudioRenderer)}.{nameof(Read)}: {ex.Message}. Stack Trace:\r\n{ex.StackTrace}"); } finally { Monitor.Exit(SyncLock); } }
/// <summary> /// The render block callback that updates the reported media position /// </summary> /// <param name="block">The block.</param> /// <param name="clockPosition">The clock position.</param> /// <param name="renderIndex">Index of the render.</param> private void RenderBlock(MediaBlock block, TimeSpan clockPosition, int renderIndex) { Renderers[block.MediaType].Render(block, clockPosition, renderIndex); Container.LogRenderBlock(block, clockPosition, renderIndex); }
/// <summary> /// Renders the specified media block. /// This needs to return immediately so the calling thread is not disturbed. /// </summary> /// <param name="mediaBlock">The media block.</param> /// <param name="clockPosition">The clock position.</param> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { var block = mediaBlock as VideoBlock; if (block == null) { return; } if (IsRenderingInProgress.Value == true) { MediaElement?.MediaCore?.Log(MediaLogMessageType.Debug, $"{nameof(VideoRenderer)}: Frame skipped at {mediaBlock.StartTime}"); return; } // Flag the start of a rendering cycle IsRenderingInProgress.Value = true; // Create an action that holds GUI thread actions var foregroundAction = new Action(() => { MediaElement.CaptionsView.RenderPacket(block, MediaCore); ApplyLayoutTransforms(block); }); var canStartForegroundTask = MediaElement.VideoView.ElementDispatcher != MediaElement.Dispatcher; var foregroundTask = canStartForegroundTask ? MediaElement.Dispatcher.InvokeAsync(foregroundAction) : null; // Ensure the target bitmap can be loaded MediaElement.VideoView.InvokeAsync(DispatcherPriority.Render, () => { if (block.IsDisposed) { IsRenderingInProgress.Value = false; return; } // Run the foreground action if we could not start it. if (foregroundTask == null) { foregroundAction(); } try { var bitmapData = LockTargetBitmap(block); if (bitmapData != null) { LoadTargetBitmapBuffer(bitmapData, block); MediaElement.RaiseRenderingVideoEvent(block, bitmapData, clockPosition); RenderTargetBitmap(block, bitmapData, clockPosition); } } catch (Exception ex) { MediaElement?.MediaCore?.Log( MediaLogMessageType.Error, $"{nameof(VideoRenderer)} {ex.GetType()}: {nameof(Render)} failed. {ex.Message}."); } finally { foregroundTask?.Wait(); IsRenderingInProgress.Value = false; } }); }
public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { }
private static IEnumerable <Block> Unroll(SelectorAndBlock block) { var ret = new List <Block>(); var props = new List <Property>(); foreach (var prop in block.Properties) { var media = prop as InnerMediaProperty; var nested = prop as NestedBlockProperty; if (media == null && nested == null) { props.Add(prop); continue; } if (nested != null) { var inner = Unroll(nested.Block); var innerMedia = inner.OfType <MediaBlock>(); var other = inner.Where(i => !(i is MediaBlock)).Cast <SelectorAndBlock>(); props.AddRange(other.Select(s => new NestedBlockProperty(s, s.Start, s.Stop))); foreach (var m in innerMedia) { var selBlock = new SelectorAndBlock( block.Selector, m.Blocks.Cast <SelectorAndBlock>().Select(s => new NestedBlockProperty(s, s.Start, s.Stop)), null, m.Start, m.Stop, m.FilePath ); var newMedia = new MediaBlock( m.MediaQuery, new List <Block> { selBlock }, m.Start, m.Stop, m.FilePath ); ret.Add(newMedia); } continue; } var unrolled = new MediaBlock( media.MediaQuery, new List <Block> { new SelectorAndBlock( block.Selector, media.Block.Properties, null, -1, -1, media.FilePath ) }, -1, -1, media.FilePath ); ret.Add(unrolled); } ret.Add(new SelectorAndBlock(block.Selector, props, null, block.Start, block.Stop, block.FilePath)); return(ret); }
/// <summary> /// Invoke when manager starts new question /// </summary> /// <param name="id">Number of question</param> /// <param name="text">Text of question</param> /// <param name="secondsToAnswer">Time in seconds to answer</param> /// <param name="kind">Type of question</param> /// <param name="answers">List of answers</param> /// <param name="mediaPath">Path to video or picture for question</param> private void QuizManager_OnNewQuestion(int id, string text, string rightAnswer, int secondsToAnswer, QuestionKind kind, List <Answer> answers, Uri mediaPath, MediaAnswer mediaAnswer) { switch (kind) { case QuestionKind.WithVideo: { ShowBlacker(); ImageAndVideoGrid.Children[0].Visibility = Visibility.Collapsed; MediaGrid.Visibility = Visibility.Visible; MediaBorder.Padding = new Thickness(200, 30, 200, 0); MediaBlock.Source = mediaPath; MediaBlock.Visibility = Visibility.Visible; MediaBlock.Play(); isVideoQuestion = true; isVideoPlay = true; break; } case QuestionKind.WithImage: { ShowBlacker(); MediaBlock.Stop(); ImageAndVideoGrid.Children.RemoveAt(0); Image image = new Image(); BitmapImage src = new BitmapImage(); src.BeginInit(); src.UriSource = mediaPath; src.EndInit(); image.Source = src; image.Stretch = Stretch.Uniform; ImageAndVideoGrid.Children.Insert(0, image); MediaGrid.Visibility = Visibility.Visible; MediaBlock.Visibility = Visibility.Collapsed; isVideoQuestion = false; break; } case QuestionKind.Simple: { HideBlacker(); MediaBlock.Stop(); MediaDockPanel.Visibility = Visibility.Collapsed; MediaBlock.Visibility = Visibility.Collapsed; isVideoQuestion = false; break; } } switch (mediaAnswer.Kind) { case AnswerKind.WithImage: { RightAnswerMediaGrid.Visibility = Visibility.Visible; RightAnswerMediaBlock.Stop(); RightAnswerMediaBlock.Visibility = Visibility.Collapsed; RightMediaInnerGrid.Children.RemoveAt(0); Image image = new Image(); BitmapImage src = new BitmapImage(); src.BeginInit(); src.UriSource = mediaAnswer.AnswerImagePath; src.EndInit(); image.Source = src; image.Stretch = Stretch.Uniform; RightMediaInnerGrid.Children.Insert(0, image); if (src.Height > SystemParameters.PrimaryScreenHeight / 2.4) { (RightMediaInnerGrid.Children[0] as Image).Height = SystemParameters.PrimaryScreenHeight / 2.4; } RightAnswerDockPanel.Margin = new Thickness(0, 20, 0, 0); break; } case AnswerKind.WithVideo: { RightAnswerMediaGrid.Visibility = Visibility.Visible; RightAnswerMediaBlock.Visibility = Visibility.Visible; RightMediaInnerGrid.Children[0].Visibility = Visibility.Collapsed; RightAnswerMediaBlock.Source = mediaAnswer.AnswerVideoPath; RightAnswerMediaBlock.Play(); RightAnswerDockPanel.Margin = new Thickness(0, 20, 0, 0); break; } case AnswerKind.Simple: { RightAnswerMediaGrid.Visibility = Visibility.Collapsed; RightAnswerDockPanel.Margin = new Thickness(0, 100, 0, 0); break; } } QuestionNumberFontSize = 33 - ((int)Math.Log10(QuestionNumber) + 1) * 2; if (text.Count() < 93) { QuestionTextBlock.VerticalAlignment = VerticalAlignment.Center; } else if (text.Count() < 185) { QuestionTextBlock.VerticalAlignment = VerticalAlignment.Top; } else { QuestionTextBlock.VerticalAlignment = VerticalAlignment.Top; text = text.Substring(0, 182) + "..."; } QuestionText = text; Regex reg = new Regex(@"\s{2,}"); text = reg.Replace(text, " "); MainWindowQuestion = text; AnswerTimerText = secondsToAnswer.ToString(); _answersTime = TimeSpan.FromSeconds(secondsToAnswer); QuestionNumber = id; RightAnswer = rightAnswer; RightAnswerGrid.Visibility = Visibility.Hidden; RightAnswerMediaBlock.Stop(); MediaGrid.Visibility = Visibility.Visible; MediaDockPanel.Visibility = Visibility.Visible; ShowImage(); }
/// <inheritdoc /> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { if (mediaBlock is VideoBlock == false) { return; } var block = (VideoBlock)mediaBlock; if (IsRenderingInProgress.Value) { if (MediaCore?.State.IsPlaying ?? false) { this.LogDebug(Aspects.VideoRenderer, $"{nameof(VideoRenderer)} frame skipped at {mediaBlock.StartTime}"); } return; } // Flag the start of a rendering cycle IsRenderingInProgress.Value = true; // Send the packets to the CC renderer MediaElement?.CaptionsView?.SendPackets(block, MediaCore); // Create an action that holds GUI thread actions var foregroundAction = new Action(() => { MediaElement?.CaptionsView?.Render(MediaElement.ClosedCaptionsChannel, clockPosition); ApplyLayoutTransforms(block); }); var canStartForegroundTask = MediaElement.VideoView.ElementDispatcher != MediaElement.Dispatcher; var foregroundTask = canStartForegroundTask ? MediaElement.Dispatcher.InvokeAsync(foregroundAction) : null; // Ensure the target bitmap can be loaded MediaElement?.VideoView?.InvokeAsync(DispatcherPriority.Render, () => { if (block.IsDisposed) { IsRenderingInProgress.Value = false; return; } // Run the foreground action if we could not start it in parallel. if (foregroundTask == null) { try { foregroundAction(); } catch (Exception ex) { this.LogError(Aspects.VideoRenderer, $"{nameof(VideoRenderer)}.{nameof(Render)} layout/CC failed.", ex); } } try { // Render the bitmap data var bitmapData = LockTargetBitmap(block); if (bitmapData == null) { return; } LoadTargetBitmapBuffer(bitmapData, block); MediaElement.RaiseRenderingVideoEvent(block, bitmapData, clockPosition); RenderTargetBitmap(bitmapData); } catch (Exception ex) { this.LogError(Aspects.VideoRenderer, $"{nameof(VideoRenderer)}.{nameof(Render)} bitmap failed.", ex); } finally { if (foregroundTask != null) { try { foregroundTask.Wait(); } catch (Exception ex) { this.LogError(Aspects.VideoRenderer, $"{nameof(VideoRenderer)}.{nameof(Render)} layout/CC failed.", ex); } } // Always reset the rendering state IsRenderingInProgress.Value = false; } }); }
private void Window_KeyUp(object sender, KeyEventArgs e) { switch (e.Key) { case Key.P: { if (isVideoQuestion) { if (isVideoPlay) { MediaBlock.Pause(); } else { MediaBlock.Play(); } isVideoPlay = !isVideoPlay; } if (isVideoRightAnswer) { if (isRightAnswerVideoPlay) { RightAnswerMediaBlock.Pause(); } else { RightAnswerMediaBlock.Play(); } isRightAnswerVideoPlay = !isRightAnswerVideoPlay; } break; } case Key.R: { if (isVideoQuestion) { MediaBlock.Stop(); MediaBlock.Play(); isVideoPlay = true; } if (isVideoRightAnswer) { MediaBlock.Stop(); MediaBlock.Play(); isRightAnswerVideoPlay = true; } break; } } if (!isQuizStarted) { return; } if (e.Key == Key.Enter) { if (isAddPointsWindowOpened) { if (ActivePlayer != null && ActivePlayer.PlayerIndex >= 0) { if (quizManager.AddedPoints()) { HideBlacker(); } else { ShowBlacker(); } isAddPointsWindowOpened = false; AddPointsMenu.Visibility = Visibility.Collapsed; if (isAddingPointNecessary) { AddPoints(ActivePlayer.PlayerIndex, Convert.ToDouble(AddingPointsTextBlock.Text)); QuizManager_OnRightAnswer(0, true); MediaGrid.Visibility = Visibility.Hidden; RightAnswerGrid.Visibility = Visibility.Visible; isAddingPointNecessary = false; return; } HideBlacker(); AddPoints(ActivePlayer.PlayerIndex, Convert.ToDouble(AddingPointsTextBlock.Text)); isAddingPointNecessary = false; closedElement.Visibility = Visibility.Visible; } } } if (e.Key == Key.Escape) { if (isAddPointsWindowOpened) { if (!isAddingPointNecessary) { AddPointsMenu.Visibility = Visibility.Hidden; closedElement.Visibility = Visibility.Visible; HideBlacker(); } } } if (isAddPointsWindowOpened) { if (Char.IsDigit((char)KeyInterop.VirtualKeyFromKey(e.Key)) && e.Key != Key.Back || e.Key == Key.Space) { if ((int)(((char)KeyInterop.VirtualKeyFromKey(e.Key)) - '0') > Players.Count || (int)(((char)KeyInterop.VirtualKeyFromKey(e.Key)) - '0') == 0) { return; } ActivePlayer = Players[(int)(((char)KeyInterop.VirtualKeyFromKey(e.Key)) - '0') - 1]; } else { return; } } switch (e.Key) { case Key.Y: { quizManager.RightAnswerClick(); break; } case Key.N: { quizManager.WrongAnswerClick(); break; } case Key.S: { quizManager.StartButtonListener(StartTimer); break; } case Key.C: { quizManager.Next(); break; } case Key.Q: { ShowBlacker(); isAddingPointNecessary = false; AddPointsMenu.Visibility = Visibility.Visible; ActivePlayer = null; if (RightAnswerGrid.Visibility == Visibility.Visible) { closedElement = RightAnswerGrid; RightAnswerGrid.Visibility = Visibility.Hidden; } else if (MediaGrid.Visibility == Visibility.Visible) { closedElement = MediaGrid; MediaGrid.Visibility = Visibility.Hidden; } else if (MainSettingsGrid.Visibility == Visibility.Visible) { closedElement = MainSettingsGrid; MainSettingsGrid.Visibility = Visibility.Hidden; } isAddPointsWindowOpened = true; quizManager.StopQuiz(); break; } } }