Exemplo n.º 1
0
        /// <summary>
        /// Kills the transcoding job.
        /// </summary>
        /// <param name="job">The job.</param>
        private void KillTranscodingJob(TranscodingJob job)
        {
            lock (_activeTranscodingJobs)
            {
                _activeTranscodingJobs.Remove(job);

                if (job.KillTimer != null)
                {
                    job.KillTimer.Dispose();
                    job.KillTimer = null;
                }
            }

            var process = job.Process;

            var hasExited = true;

            try
            {
                hasExited = process.HasExited;
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
            }

            if (!hasExited)
            {
                try
                {
                    Logger.Info("Killing ffmpeg process for {0}", job.Path);

                    process.Kill();

                    // Need to wait because killing is asynchronous
                    process.WaitForExit(5000);
                }
                catch (Win32Exception ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
                catch (InvalidOperationException ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
                catch (NotSupportedException ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
            }

            // Determine if it exited successfully
            var hasExitedSuccessfully = false;

            try
            {
                hasExitedSuccessfully = process.ExitCode == 0;
            }
            catch (InvalidOperationException)
            {
            }
            catch (NotSupportedException)
            {
            }

            // Dispose the process
            process.Dispose();

            // If it didn't complete successfully cleanup the partial files
            // Also don't cache output from resume points
            // Also don't cache video
            if (!hasExitedSuccessfully || job.StartTimeTicks.HasValue || job.IsVideo)
            {
                DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
            }
        }
Exemplo n.º 2
0
        private async void PingTimer(TranscodingJob job, bool isProgressCheckIn)
        {
            if (job.HasExited)
            {
                job.StopKillTimer();
                return;
            }

            var timerDuration = 10000;

            if (job.Type != TranscodingJobType.Progressive)
            {
                timerDuration = 60000;
            }

            job.PingTimeout = timerDuration;
            job.LastPingDate = DateTime.UtcNow;

            // Don't start the timer for playback checkins with progressive streaming
            if (job.Type != TranscodingJobType.Progressive || !isProgressCheckIn)
            {
                job.StartKillTimer(OnTranscodeKillTimerStopped);
            }
            else
            {
                job.ChangeKillTimerIfStarted();
            }

            if (!string.IsNullOrWhiteSpace(job.LiveStreamId))
            {
                try
                {
                    await _mediaSourceManager.PingLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("Error closing live stream", ex);
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Kills the transcoding job.
        /// </summary>
        /// <param name="job">The job.</param>
        /// <param name="closeLiveStream">if set to <c>true</c> [close live stream].</param>
        /// <param name="delete">The delete.</param>
        private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func<string, bool> delete)
        {
            job.DisposeKillTimer();

            Logger.Debug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);

            lock (_activeTranscodingJobs)
            {
                _activeTranscodingJobs.Remove(job);

                if (!job.CancellationTokenSource.IsCancellationRequested)
                {
                    job.CancellationTokenSource.Cancel();
                }
            }

            lock (job.ProcessLock)
            {
                if (job.TranscodingThrottler != null)
                {
                    job.TranscodingThrottler.Stop();
                }

                var process = job.Process;

                var hasExited = job.HasExited;

                if (!hasExited)
                {
                    try
                    {
                        Logger.Info("Stopping ffmpeg process with q command for {0}", job.Path);

                        //process.Kill();
                        process.StandardInput.WriteLine("q");

                        // Need to wait because killing is asynchronous
                        if (!process.WaitForExit(5000))
                        {
                            Logger.Info("Killing ffmpeg process for {0}", job.Path);
                            process.Kill();
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                    }
                }
            }

            if (delete(job.Path))
            {
                DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
            }

            if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId))
            {
                try
                {
                    await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("Error closing live stream for {0}", ex, job.Path);
                }
            }
        }
Exemplo n.º 4
0
        public void OnTranscodeBeginRequest(TranscodingJob job)
        {
            job.ActiveRequestCount++;

            if (string.IsNullOrWhiteSpace(job.PlaySessionId) || job.Type == TranscodingJobType.Progressive)
            {
                job.StopKillTimer();
            }
        }
Exemplo n.º 5
0
 public void OnTranscodeEndRequest(TranscodingJob job)
 {
     job.ActiveRequestCount--;
     //Logger.Debug("OnTranscodeEndRequest job.ActiveRequestCount={0}", job.ActiveRequestCount);
     if (job.ActiveRequestCount <= 0)
     {
         PingTimer(job, false);
     }
 }
Exemplo n.º 6
0
        /// <summary>
        /// Called when [transcode beginning].
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="playSessionId">The play session identifier.</param>
        /// <param name="liveStreamId">The live stream identifier.</param>
        /// <param name="transcodingJobId">The transcoding job identifier.</param>
        /// <param name="type">The type.</param>
        /// <param name="process">The process.</param>
        /// <param name="deviceId">The device id.</param>
        /// <param name="state">The state.</param>
        /// <param name="cancellationTokenSource">The cancellation token source.</param>
        /// <returns>TranscodingJob.</returns>
        public TranscodingJob OnTranscodeBeginning(string path,
            string playSessionId,
            string liveStreamId,
            string transcodingJobId,
            TranscodingJobType type,
            Process process,
            string deviceId,
            StreamState state,
            CancellationTokenSource cancellationTokenSource)
        {
            lock (_activeTranscodingJobs)
            {
                var job = new TranscodingJob(Logger)
                {
                    Type = type,
                    Path = path,
                    Process = process,
                    ActiveRequestCount = 1,
                    DeviceId = deviceId,
                    CancellationTokenSource = cancellationTokenSource,
                    Id = transcodingJobId,
                    PlaySessionId = playSessionId,
                    LiveStreamId = liveStreamId
                };

                _activeTranscodingJobs.Add(job);

                ReportTranscodingProgress(job, state, null, null, null, null, null);

                return job;
            }
        }
Exemplo n.º 7
0
        public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
        {
            var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;

            if (job != null)
            {
                job.Framerate = framerate;
                job.CompletionPercentage = percentComplete;
                job.TranscodingPositionTicks = ticks;
                job.BytesTranscoded = bytesTranscoded;
                job.BitRate = bitRate;
            }

            var deviceId = state.Request.DeviceId;

            if (!string.IsNullOrWhiteSpace(deviceId))
            {
                var audioCodec = state.ActualOutputAudioCodec;
                var videoCodec = state.ActualOutputVideoCodec;

                _sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo
                {
                    Bitrate = bitRate ?? state.TotalOutputBitrate,
                    AudioCodec = audioCodec,
                    VideoCodec = videoCodec,
                    Container = state.OutputContainer,
                    Framerate = framerate,
                    CompletionPercentage = percentComplete,
                    Width = state.OutputWidth,
                    Height = state.OutputHeight,
                    AudioChannels = state.OutputAudioChannels,
                    IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
                    IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
                });
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Kills the transcoding job.
        /// </summary>
        /// <param name="job">The job.</param>
        /// <param name="delete">The delete.</param>
        private void KillTranscodingJob(TranscodingJob job, Func<string, bool> delete)
        {
            lock (_activeTranscodingJobs)
            {
                _activeTranscodingJobs.Remove(job);

                if (!job.CancellationTokenSource.IsCancellationRequested)
                {
                    job.CancellationTokenSource.Cancel();
                }

                if (job.KillTimer != null)
                {
                    job.KillTimer.Dispose();
                    job.KillTimer = null;
                }
            }

            lock (job.ProcessLock)
            {
                var process = job.Process;

                var hasExited = true;

                try
                {
                    hasExited = process.HasExited;
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
                }

                if (!hasExited)
                {
                    try
                    {
                        Logger.Info("Killing ffmpeg process for {0}", job.Path);

                        //process.Kill();
                        process.StandardInput.WriteLine("q");

                        // Need to wait because killing is asynchronous
                        process.WaitForExit(5000);
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                    }
                }
            }

            if (delete(job.Path))
            {
                DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Kills the transcoding job.
        /// </summary>
        /// <param name="job">The job.</param>
        /// <param name="closeLiveStream">if set to <c>true</c> [close live stream].</param>
        /// <param name="delete">The delete.</param>
        private async Task KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func <string, bool> delete)
        {
            job.DisposeKillTimer();

            _logger.LogDebug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);

            lock (_activeTranscodingJobs)
            {
                _activeTranscodingJobs.Remove(job);

                if (!job.CancellationTokenSource.IsCancellationRequested)
                {
                    job.CancellationTokenSource.Cancel();
                }
            }

            lock (_transcodingLocks)
            {
                _transcodingLocks.Remove(job.Path);
            }

            lock (job.ProcessLock)
            {
                job.TranscodingThrottler?.Stop().GetAwaiter().GetResult();

                var process = job.Process;

                var hasExited = job.HasExited;

                if (!hasExited)
                {
                    try
                    {
                        _logger.LogInformation("Stopping ffmpeg process with q command for {Path}", job.Path);

                        process.StandardInput.WriteLine("q");

                        // Need to wait because killing is asynchronous
                        if (!process.WaitForExit(5000))
                        {
                            _logger.LogInformation("Killing ffmpeg process for {Path}", job.Path);
                            process.Kill();
                        }
                    }
                    catch (InvalidOperationException)
                    {
                    }
                }
            }

            if (delete(job.Path))
            {
                await DeletePartialStreamFiles(job.Path, job.Type, 0, 1500).ConfigureAwait(false);
            }

            if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId))
            {
                try
                {
                    await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error closing live stream for {Path}", job.Path);
                }
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Kills the transcoding job.
        /// </summary>
        /// <param name="job">The job.</param>
        private void KillTranscodingJob(TranscodingJob job)
        {
            lock (_activeTranscodingJobs)
            {
                _activeTranscodingJobs.Remove(job);

                if (!job.CancellationTokenSource.IsCancellationRequested)
                {
                    job.CancellationTokenSource.Cancel();
                }

                if (job.KillTimer != null)
                {
                    job.KillTimer.Dispose();
                    job.KillTimer = null;
                }
            }

            var process = job.Process;

            var hasExited = true;

            try
            {
                hasExited = process.HasExited;
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
            }

            if (!hasExited)
            {
                try
                {
                    Logger.Info("Killing ffmpeg process for {0}", job.Path);

                    process.Kill();

                    // Need to wait because killing is asynchronous
                    process.WaitForExit(5000);
                }
                catch (Win32Exception ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
                catch (InvalidOperationException ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
                catch (NotSupportedException ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
            }

            // Dispose the process
            process.Dispose();

            DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
        }
Exemplo n.º 11
0
        /// <summary>
        /// Kills the transcoding job.
        /// </summary>
        /// <param name="job">The job.</param>
        /// <param name="closeLiveStream">if set to <c>true</c> [close live stream].</param>
        /// <param name="delete">The delete.</param>
        private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func <string, bool> delete)
        {
            job.DisposeKillTimer();

            Logger.Debug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);

            lock (_activeTranscodingJobs)
            {
                _activeTranscodingJobs.Remove(job);

                if (!job.CancellationTokenSource.IsCancellationRequested)
                {
                    job.CancellationTokenSource.Cancel();
                }
            }

            lock (job.ProcessLock)
            {
                if (job.TranscodingThrottler != null)
                {
                    job.TranscodingThrottler.Stop();
                }

                var process = job.Process;

                var hasExited = job.HasExited;

                if (!hasExited)
                {
                    try
                    {
                        Logger.Info("Killing ffmpeg process for {0}", job.Path);

                        //process.Kill();
                        process.StandardInput.WriteLine("q");

                        // Need to wait because killing is asynchronous
                        process.WaitForExit(5000);
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                    }
                }
            }

            if (delete(job.Path))
            {
                DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
            }

            if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId))
            {
                try
                {
                    await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("Error closing live stream for {0}", ex, job.Path);
                }
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// Kills the transcoding job.
        /// </summary>
        /// <param name="job">The job.</param>
        private async void KillTranscodingJob(TranscodingJob job)
        {
            lock (_activeTranscodingJobs)
            {
                _activeTranscodingJobs.Remove(job);

                if (job.KillTimer != null)
                {
                    job.KillTimer.Dispose();
                    job.KillTimer = null;
                }
            }

            var process = job.Process;

            var hasExited = true;

            try
            {
                hasExited = process.HasExited;
            }
            catch (Win32Exception ex)
            {
                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
            }
            catch (InvalidOperationException ex)
            {
                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
            }
            catch (NotSupportedException ex)
            {
                Logger.ErrorException("Error determining if ffmpeg process has exited for {0}", ex, job.Path);
            }

            if (!hasExited)
            {
                try
                {
                    Logger.Info("Killing ffmpeg process for {0}", job.Path);

                    process.Kill();

                    // Need to wait because killing is asynchronous
                    process.WaitForExit(5000);
                }
                catch (Win32Exception ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
                catch (InvalidOperationException ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
                catch (NotSupportedException ex)
                {
                    Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
                }
            }

            // Determine if it exited successfully
            var hasExitedSuccessfully = false;

            try
            {
                hasExitedSuccessfully = process.ExitCode == 0;
            }
            catch (InvalidOperationException)
            {

            }
            catch (NotSupportedException)
            {

            }

            // Dispose the process
            process.Dispose();

            // If it didn't complete successfully cleanup the partial files
            // Also don't cache output from resume points
            // Also don't cache video
            if (!hasExitedSuccessfully || job.StartTimeTicks.HasValue || job.IsVideo)
            {
                Logger.Info("Deleting partial stream file(s) {0}", job.Path);

                await Task.Delay(1000).ConfigureAwait(false);

                try
                {
                    if (job.Type == TranscodingJobType.Progressive)
                    {
                        DeleteProgressivePartialStreamFiles(job.Path);
                    }
                    else
                    {
                        DeleteHlsPartialStreamFiles(job.Path);
                    }
                }
                catch (IOException ex)
                {
                    Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, job.Path);
                }
            }
        }
Exemplo n.º 13
0
        public void OnTranscodeEndRequest(TranscodingJob job)
        {
            job.ActiveRequestCount--;

            if (job.ActiveRequestCount == 0)
            {
                // The HLS kill timer is long - 1/2 hr. clients should use the manual kill command when stopping.
                var timerDuration = job.Type == TranscodingJobType.Progressive ? 1000 : 1800000;

                if (job.KillTimer == null)
                {
                    job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite);
                }
                else
                {
                    job.KillTimer.Change(timerDuration, Timeout.Infinite);
                }
            }
        }
Exemplo n.º 14
0
        public void OnTranscodeEndRequest(TranscodingJob job)
        {
            job.ActiveRequestCount--;

            if (job.ActiveRequestCount == 0)
            {
                if (job.Type == TranscodingJobType.Progressive)
                {
                    const int timerDuration = 1000;

                    if (job.KillTimer == null)
                    {
                        job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite);
                    }
                    else
                    {
                        job.KillTimer.Change(timerDuration, Timeout.Infinite);
                    }
                }
            }
        }