Example #1
0
        internal void Start()
        {
            this.videoProvider = VideoProviderFactory.Create(this.region);
            this.actions       = this.task.Actions.Select(a => {
                try {
                    // set options if needed
                    if (a.Options != null &&
                        Application.PluginManager.Actions.First(a2 => a2.Type.Name == a.ActionType).Configurable)
                    {
                        // create uninitialized instance
                        var action = FormatterServices.GetSafeUninitializedObject(
                            Type.GetType(a.ActionType, true, true) ??
                            throw new InvalidOperationException(Resources.TaskHelper_NoSuchActionMessage)) as Action;

                        // set options property
                        a.GetType().GetProperty("Options")?.SetValue(action, a.Options);

                        // call parameterless constructor
                        action?.GetType()
                        .GetConstructor(
                            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                            null,
                            Type.EmptyTypes,
                            null)
                        ?.Invoke(action, new object[] { this.codec });
                    }

                    return(Activator.CreateInstance(Type.GetType(a.ActionType) ??
                                                    throw new InvalidOperationException(
                                                        Resources.TaskHelper_NoSuchActionMessage),
                                                    this.codec) as Action);
                } catch (Exception exception) {
                    Log.WriteLine(LogLevel.Warning, $"error initializing action {a.ActionType}: {exception}");

                    // create dummy action for displaying error
                    var action = new Action(this.codec);
                    action.SetStatus(ActionStatus.Failed,
                                     new Exception(Resources.TaskHelper_ActionInitializationFailedCaption, exception));
                    return(action);
                }
            })
                                 .Where(a => a != null)
                                 .ToList();

            this.stream = new MultiStream();
            this.actions.ForEach(a => {
                this.stream.Add(a);
                Application.ActionManager.AddAction(a);
            });

            if (this.codec is ID3D11Codec acceleratedCodec &&
                this.videoProvider is ID3D11VideoProvider acceleratedVideoProvider &&
                acceleratedVideoProvider.SurfacePointer != IntPtr.Zero)
            {
                acceleratedCodec.SurfacePointer = acceleratedVideoProvider.SurfacePointer;
                this.isAcceleratedEncoding      = true;
                Log.WriteLine(LogLevel.Informational, "performing hardware-assisted encoding");
            }

            this.codec?.Initialize(this.videoProvider.CaptureBounds.Size, this.stream);

            this.recordingThread = new Thread(Record)
            {
                Priority = ThreadPriority.Highest
            };
            this.recordingThread.SetApartmentState(ApartmentState.MTA);
            this.recordingThread.Start();

            State = RecordingState.Recording;
            Application.TrayIcon.AnimateIndicator(IndicatorStatus.Recording, 500);
        }
Example #2
0
        /// <summary>
        ///   Captures an still image, encodes it and executes each bound action.
        /// </summary>
        /// <param name="task">Task to be run.</param>
        /// <param name="rect">Rectangle to be captured.</param>
        /// <returns>An enumeration of the <see cref="Common.Action" />s running.</returns>
        private static void StartScreenshotTask(Task task, Rectangle rect)
        {
            IBitmapVideoProvider provider = null;
            BitmapData           bmpData  = default;
            Bitmap thumbnail;

            try {
                // create video provider
                provider = VideoProviderFactory.Create(rect);

                // acquire frame and lock frame bits for reading so that codecs can work over it
                provider.AcquireFrame();
                bmpData = provider.LockFrameBitmap();

                // generate thumbnail
                thumbnail = new Bitmap(bmpData.Width, bmpData.Height);
                // TODO: debug this
                System.Drawing.Imaging.BitmapData data = thumbnail.LockBits(new Rectangle(Point.Empty, thumbnail.Size),
                                                                            ImageLockMode.WriteOnly,
                                                                            PixelFormat.Format32bppArgb);
                Utilities.CopyMemory(data.Scan0, bmpData.Scan0, bmpData.Height * bmpData.Stride);
                thumbnail.UnlockBits(data);

                using (var tempBmp = new Bitmap(4 * (Resources.NeutralResultOverlay.Width - 48),
                                                4 * (Resources.NeutralResultOverlay.Height - 48))) {
                    using (Graphics graphics = Graphics.FromImage(tempBmp)) {
                        graphics.DrawImage(thumbnail,
                                           new Rectangle(Point.Empty, tempBmp.Size),
                                           new Rectangle(Point.Empty, thumbnail.Size),
                                           GraphicsUnit.Pixel);
                    }

                    thumbnail.Dispose();
                    thumbnail = tempBmp.Clone() as Bitmap;
                }
            } catch (Exception exception) {
                Log.WriteLine(LogLevel.Error, $"video provider exception: ${exception}");
                if (bmpData.Scan0 == default)
                {
                    provider?.UnlockFrameBitmap(bmpData);
                }

                provider?.ReleaseFrame();
                provider?.Dispose();
                throw new TaskException(Resources.TaskHelper_CaptureFailedCaption,
                                        Resources.TaskHelper_CaptureFailedContent,
                                        exception);
            }

            // initialize codec
            IStillImageCodec codec;

            try {
                // get uninitialized object in case we need to set Options property first
                codec = Activator.CreateInstance(Type.GetType(task.Codec.CodecType, true, true) ??
                                                 throw new InvalidOperationException("No such codec loaded.")) as
                        IStillImageCodec;

                if (task.Codec.Options is Dictionary <string, object> userOptions &&
                    codec is IHasOptions configurableObject)
                {
                    // set user options
                    configurableObject.Options = configurableObject.Options ?? new Dictionary <string, object>();

                    foreach (KeyValuePair <string, object> pair in userOptions)
                    {
                        configurableObject.Options[pair.Key] = pair.Value;
                    }
                }
            } catch (Exception exception) {
                Log.WriteLine(LogLevel.Error, $"error initializing codec {task.Codec.CodecType}: {exception}");
                throw new TaskException(Resources.TaskHelper_EncodingFailedCaption,
                                        Resources.TaskHelper_EncodingInitializationFailedContent,
                                        exception);
            }

            // create temporary memory stream for holding the encoded data
            var stream = new MemoryStream();

            try {
                // encode the still image
                codec?.Encode(bmpData, stream);
            } catch (Exception exception) {
                Log.WriteLine(LogLevel.Error, $"error encoding still image: {exception}");

                stream.Dispose();
                provider.UnlockFrameBitmap(bmpData);
                provider.ReleaseFrame();
                provider.Dispose();
                thumbnail?.Dispose();

                throw new TaskException(Resources.TaskHelper_EncodingFailedCaption,
                                        Resources.TaskHelper_EncodingFailedContent,
                                        exception);
            }

            List <Action> actions = task.Actions.Select(a => {
                try {
                    // set options if needed
                    if (a.Options != null &&
                        Application.PluginManager.Actions.First(a2 => a2.Type.Name == a.ActionType).Configurable)
                    {
                        // create uninitialized instance
                        var action = FormatterServices.GetSafeUninitializedObject(
                            Type.GetType(a.ActionType, true, true) ??
                            throw new InvalidOperationException(Resources.TaskHelper_NoSuchActionMessage)) as Action;

                        // set options property
                        a.GetType().GetProperty("Options")?.SetValue(action, a.Options);

                        // call parameterless constructor
                        action?.GetType()
                        .GetConstructor(
                            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                            null,
                            Type.EmptyTypes,
                            null)
                        ?.Invoke(action, new object[] { codec });
                    }

                    return(Activator.CreateInstance(Type.GetType(a.ActionType) ??
                                                    throw new InvalidOperationException(
                                                        Resources.TaskHelper_NoSuchActionMessage),
                                                    codec) as Action);
                } catch (Exception exception) {
                    Log.WriteLine(LogLevel.Warning, $"error initializing action {a.ActionType}: {exception}");

                    // create dummy action for displaying error
                    var action = new Action(codec);
                    action.SetStatus(ActionStatus.Failed,
                                     new Exception(Resources.TaskHelper_ActionInitializationFailedCaption, exception));
                    return(action);
                }
            })
                                    .Where(a => a != null)
                                    .ToList();

            actions.ForEach(a => {
                Application.ActionManager.AddAction(a);

                void Release()
                {
                    if (a == actions.Last())
                    {
                        // this was the last action, release the temporary stream. It's not disposed unless the last stream
                        // fails to initialize
                        // ReSharper disable once AccessToDisposedClosure
                        Log.WriteLine(LogLevel.Debug, "releasing resources");
                        stream.Dispose();
                        provider.UnlockFrameBitmap(bmpData);
                        provider.ReleaseFrame();
                        provider.Dispose();
                        GC.Collect();
                    }
                }

                // set preview bitmap
                a.Thumbnail = thumbnail;

                try {
                    if (a is IFiltered filteredAction)
                    {
                        if (!filteredAction.GetMediaAcceptance(task.TaskType, codec, task.Codec.Options as ICodecParameters))
                        {
                            Log.WriteLine(LogLevel.Warning, "media filter did not accept this capture");
                            throw new Exception(Resources.TaskHelper_UnsupportedMediaMessage);
                        }
                    }

                    if (a is IPreBitmapEncodingAction preEncodingAction)
                    {
                        // set bitmap data instead of copying to the stream
                        Log.WriteLine(LogLevel.Debug, $"setting bitmap data for {a.GetType().Name}");
                        preEncodingAction.SetBitmapData(bmpData);
                        Release();
                        a.SetStatus(ActionStatus.Success);
                        Log.WriteLine(LogLevel.Informational, $"action {a.GetType().Name} is done");
                    }
                    else
                    {
                        // copy data to the action stream
                        Log.WriteLine(LogLevel.Debug, $"writing {stream.Length} bytes to {a.GetType().Name}");
                        a.SetLength(stream.Length);

                        new Thread(() => {
                            using (var target = new BufferedStream(a, a.BufferSize)) { stream.WriteTo(target); }
                            a.Flush();
                            a.Dispose();
                            Release();
                            Log.WriteLine(LogLevel.Informational, $"action {a.GetType().Name} is ready");
                        }).Start();
                    }
                } catch (Exception exception) {
                    Release();
                    Log.WriteLine(LogLevel.Warning, $"error copying to action stream {a.GetType().Name}: {exception}");
                    a.SetStatus(ActionStatus.Failed, new Exception(Resources.TaskHelper_ActionFailedCaption, exception));
                }
            });
        }