/// <summary>
        /// Sets the entry thumbnail.
        /// Deletes the prior thumbnail file is found or previously set.
        /// </summary>
        /// <param name="mediaUrl">The media URL.</param>
        /// <param name="bitmap">The bitmap.</param>
        public void AddOrUpdateEntryThumbnail(string mediaUrl, BitmapDataBuffer bitmap)
        {
            lock (SyncRoot)
            {
                var entry = FindEntryByMediaUrl(mediaUrl);
                if (entry == null)
                {
                    return;
                }

                if (entry.Thumbnail != null)
                {
                    var existingThumbnailFilePath = Path.Combine(ViewModel.ThumbsDirectory, entry.Thumbnail);
                    if (File.Exists(existingThumbnailFilePath))
                    {
                        File.Delete(existingThumbnailFilePath);
                    }

                    entry.Thumbnail = null;
                }

                using (var bmp = bitmap.CreateDrawingBitmap())
                {
                    entry.Thumbnail = ThumbnailGenerator.SnapThumbnail(bmp, ViewModel.ThumbsDirectory);
                }
            }
        }
Exemplo n.º 2
0
        private void RenderTarget(VideoBlock block, BitmapDataBuffer bitmapData, TimeSpan clockPosition)
        {
            try
            {
                if (RaiseVideoEventOnGui)
                {
                    MediaElement.RaiseRenderingVideoEvent(block, bitmapData, clockPosition);
                }

                // Signal an update on the rendering surface
                TargetBitmap.AddDirtyRect(bitmapData.UpdateRect);
                TargetBitmap.Unlock();
                ApplyScaleTransform(block);
            }
            catch (Exception ex)
            {
                MediaElement?.MediaCore?.Log(
                    MediaLogMessageType.Error,
                    $"{nameof(VideoRenderer)} {ex.GetType()}: {ex.Message}. Stack Trace:\r\n{ex.StackTrace}");
            }
            finally
            {
                IsRenderingInProgress.Value = false;
            }
        }
            public unsafe BitmapDataBuffer Write(VideoBlock block)
            {
                lock (SyncLock)
                {
                    if (IsDisposed)
                    {
                        return(null);
                    }

                    EnsureBuffers(block);

                    // Compute a safe number of bytes to copy
                    // At this point, we it is assumed the strides are equal
                    var bufferLength = Math.Min(block.BufferLength, BackBufferView.Capacity);
                    var scan0        = BackBufferView.SafeMemoryMappedViewHandle.DangerousGetHandle();

                    // Copy the block data into the back buffer of the target bitmap.
                    Buffer.MemoryCopy(
                        block.Buffer.ToPointer(),
                        scan0.ToPointer(),
                        bufferLength,
                        bufferLength);

                    if (BitmapData == null || BitmapData.Scan0 != scan0)
                    {
                        BitmapData = new BitmapDataBuffer(
                            scan0, block.PictureBufferStride, block.PixelWidth, block.PixelHeight, Parent.DpiX, Parent.DpiY);
                    }

                    BackBufferView.Flush();
                    return(BitmapData);
                }
            }
Exemplo n.º 4
0
        /// <summary>
        /// Initializes the target bitmap if not available and locks it for loading the back-buffer.
        /// </summary>
        /// <param name="block">The block.</param>
        /// <param name="priority">The priority.</param>
        /// <returns>
        /// The locking result. Returns a null pointer on back buffer for invalid.
        /// </returns>
        private BitmapDataBuffer LockTarget(VideoBlock block, DispatcherPriority priority)
        {
            // Result will be set on the GUI thread
            BitmapDataBuffer result = null;

            WindowsPlatform.Instance.Gui?.Invoke(priority, () =>
            {
                // Skip the locking if scrubbing is not enabled
                if (MediaElement.ScrubbingEnabled == false && MediaElement.IsPlaying == false)
                {
                    return;
                }

                // Figure out what we need to do
                var needsCreation      = TargetBitmap == null && MediaElement.HasVideo;
                var needsModification  = needsCreation == false && (TargetBitmap.PixelWidth != block.PixelWidth || TargetBitmap.PixelHeight != block.PixelHeight);
                var hasValidDimensions = block.PixelWidth > 0 && block.PixelHeight > 0;

                // Instantiate or update the target bitmap
                if ((needsCreation || needsModification) && hasValidDimensions)
                {
                    TargetBitmap = new WriteableBitmap(
                        block.PixelWidth, block.PixelHeight, DpiX, DpiY, MediaPixelFormats[Constants.Video.VideoPixelFormat], null);
                }
                else if (hasValidDimensions == false)
                {
                    TargetBitmap = null;
                }

                // Update the target ViewBox image if not already set
                if (MediaElement.VideoView.Source != TargetBitmap)
                {
                    MediaElement.VideoView.Source = TargetBitmap;
                }

                // Don't set the result
                if (TargetBitmap == null)
                {
                    return;
                }

                // Lock the back-buffer and create a pointer to it
                TargetBitmap.Lock();
                result = BitmapDataBuffer.FromWriteableBitmap(TargetBitmap);

                if (LoadBlockBufferOnGui)
                {
                    LoadTarget(result, block);
                }
            });

            return(result);
        }
Exemplo n.º 5
0
 /// <summary>
 /// Renders the target bitmap.
 /// </summary>
 /// <param name="bitmapData">The bitmap data.</param>
 private void RenderTargetBitmap(BitmapDataBuffer bitmapData)
 {
     try
     {
         // Signal an update on the rendering surface
         TargetBitmap?.AddDirtyRect(bitmapData.UpdateRect);
         TargetBitmap?.Unlock();
     }
     catch (Exception ex)
     {
         this.LogError(Aspects.VideoRenderer, $"{nameof(VideoRenderer)}.{nameof(RenderTargetBitmap)}", ex);
     }
 }
Exemplo n.º 6
0
        /// <summary>
        /// Loads that target data buffer with block data
        /// </summary>
        /// <param name="target">The target.</param>
        /// <param name="source">The source.</param>
        private void LoadTargetBitmapBuffer(BitmapDataBuffer target, VideoBlock source)
        {
            if (source != null && source.TryAcquireReaderLock(out var readLock))
            {
                using (readLock)
                {
                    // Compute a safe number of bytes to copy
                    // At this point, we it is assumed the strides are equal
                    var bufferLength = Convert.ToUInt32(Math.Min(source.BufferLength, target.BufferLength));

                    // Copy the block data into the back buffer of the target bitmap.
                    WindowsNativeMethods.Instance.CopyMemory(target.Scan0, source.Buffer, bufferLength);
                }
            }
        }
Exemplo n.º 7
0
 /// <summary>
 /// Renders the target bitmap.
 /// </summary>
 /// <param name="bitmapData">The bitmap data.</param>
 /// <param name="clockPosition">The clock position.</param>
 private void RenderTargetBitmap(BitmapDataBuffer bitmapData, TimeSpan clockPosition)
 {
     try
     {
         // Signal an update on the rendering surface
         TargetBitmap?.AddDirtyRect(bitmapData.UpdateRect);
         TargetBitmap?.Unlock();
     }
     catch (Exception ex)
     {
         MediaElement?.MediaCore?.Log(
             MediaLogMessageType.Error,
             $"{nameof(VideoRenderer)} {ex.GetType()}: {ex.Message}. Stack Trace:\r\n{ex.StackTrace}");
     }
 }
        internal void RaiseRenderingVideoEvent(VideoBlock videoBlock, BitmapDataBuffer bitmap, TimeSpan clock)
        {
            if (RenderingVideo == null)
            {
                return;
            }

            var e = new RenderingVideoEventArgs(
                bitmap,
                MediaCore.MediaInfo.Streams[videoBlock.StreamIndex],
                videoBlock.ClosedCaptions,
                videoBlock.SmtpeTimecode,
                videoBlock.DisplayPictureNumber,
                videoBlock.StartTime,
                videoBlock.Duration,
                clock);

            RenderingVideo?.Invoke(this, e);
        }
Exemplo n.º 9
0
 /// <summary>
 /// Loads that target data buffer with block data
 /// </summary>
 /// <param name="target">The target.</param>
 /// <param name="source">The source.</param>
 private void LoadTargetBitmapBuffer(BitmapDataBuffer target, VideoBlock source)
 {
     // Copy the block data into the back buffer of the target bitmap.
     if (target.Stride == source.BufferStride)
     {
         WindowsNativeMethods.Instance.CopyMemory(target.Scan0, source.Buffer, Convert.ToUInt32(source.BufferLength));
     }
     else
     {
         var format        = MediaPixelFormats[Constants.Video.VideoPixelFormat];
         var bytesPerPixel = format.BitsPerPixel / 8;
         var copyLength    = Convert.ToUInt32(Math.Min(target.Stride, source.BufferStride));
         Parallel.For(0, source.PixelHeight, (i) =>
         {
             var sourceOffset = source.Buffer + (i * source.BufferStride);
             var targetOffset = target.Scan0 + (i * target.Stride);
             WindowsNativeMethods.Instance.CopyMemory(targetOffset, sourceOffset, copyLength);
         });
     }
 }
Exemplo n.º 10
0
        /// <summary>
        /// Loads that target data buffer with block data
        /// </summary>
        /// <param name="target">The target.</param>
        /// <param name="source">The source.</param>
        private unsafe void LoadTargetBitmapBuffer(BitmapDataBuffer target, VideoBlock source)
        {
            if (source == null || !source.TryAcquireReaderLock(out var readLock))
            {
                return;
            }

            using (readLock)
            {
                // Compute a safe number of bytes to copy
                // At this point, we it is assumed the strides are equal
                var bufferLength = Math.Min(source.BufferLength, target.BufferLength);

                // Copy the block data into the back buffer of the target bitmap.
                Buffer.MemoryCopy(
                    source.Buffer.ToPointer(),
                    target.Scan0.ToPointer(),
                    bufferLength,
                    bufferLength);
            }
        }
Exemplo n.º 11
0
        public void RenderAndBlend(int current, BitmapDataBuffer data)
        {
            UpdateRenderSize(data.PixelWidth, data.PixelHeight);
            var updated  = 0;
            var imageRaw = ass_render_frame(_renderer, _track, current, ref updated);

            if (imageRaw == IntPtr.Zero)
            {
                return;
            }
            try
            {
                unsafe
                {
                    var sourceRaw = (uint *)data.Scan0.ToPointer();
                    int srcStride = data.Stride / sizeof(uint);
                    while (imageRaw != IntPtr.Zero)
                    {
                        var image = Marshal.PtrToStructure <ASS_Image>(imageRaw);
                        var imgRaw = (byte *)image.bitmap.ToPointer();
                        int h = image.h, w = image.w;
                        if (h != 0 && w != 0)
                        {
                            int  dstStride = image.stride;
                            uint color = image.color;
                            int  srcCurrentPixel, dstCurrentPixel;
                            uint image1Pixel;
                            byte image2Pixel;
                            uint srcRed, dstRed, finRed;
                            uint srcGreen, dstGreen, finGreen;
                            uint srcBlue, dstBlue, finBlue;
                            uint dstAlpha, srcAlpha, finAlpha;

                            // RGBA
                            dstAlpha = 255 - (color & 0xFF);
                            dstRed   = ((color >> 24) & 0xFF) * dstAlpha / 255;
                            dstGreen = ((color >> 16) & 0xFF) * dstAlpha / 255;
                            dstBlue  = ((color >> 8) & 0xFF) * dstAlpha / 255;

                            for (var x = 0; x < w; x++)
                            {
                                for (var y = 0; y < h; y++)
                                {
                                    srcCurrentPixel = (y + image.dst_y) * srcStride + x + image.dst_x;
                                    dstCurrentPixel = y * dstStride + x;
                                    image1Pixel     = sourceRaw[srcCurrentPixel];
                                    image2Pixel     = imgRaw[dstCurrentPixel];

                                    // ARGB
                                    srcAlpha = ((image1Pixel >> 24) & 0xFF);
                                    srcRed   = ((image1Pixel >> 16) & 0xFF) * srcAlpha / 255;
                                    srcGreen = ((image1Pixel >> 8) & 0xFF) * srcAlpha / 255;
                                    srcBlue  = (image1Pixel & 0xFF) * srcAlpha / 255;

                                    uint dstAlpha2 = image2Pixel;
                                    uint srcAlpha2 = 255 - dstAlpha2;

                                    finRed   = dstRed * dstAlpha2 / 255 + srcRed * srcAlpha2 / 255;
                                    finGreen = dstGreen * dstAlpha2 / 255 + srcGreen * srcAlpha2 / 255;
                                    finBlue  = dstBlue * dstAlpha2 / 255 + srcBlue * srcAlpha2 / 255;
                                    finAlpha = dstAlpha2 + srcAlpha * srcAlpha2 / 256;

                                    // ARGB
                                    sourceRaw[srcCurrentPixel] =
                                        finBlue | finGreen << 8 | finRed << 16 | finAlpha << 24;
                                }
                            }
                        }

                        imageRaw = image.next;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(@"[libass] Exception rendering subtitle: " + e);
            }
        }
Exemplo n.º 12
0
 private void Me_RenderingVideo(object sender, RenderingVideoEventArgs e)
 {
     bmpBuffer = e.Bitmap;
 }