Esempio n. 1
0
        /// <summary>
        /// Gets the command line arguments.
        /// </summary>
        /// <param name="outputPath">The output path.</param>
        /// <param name="state">The state.</param>
        /// <param name="performSubtitleConversions">if set to <c>true</c> [perform subtitle conversions].</param>
        /// <returns>System.String.</returns>
        /// <exception cref="System.InvalidOperationException">Only aac and mp3 audio codecs are supported.</exception>
        protected override string GetCommandLineArguments(string outputPath, StreamState state, bool performSubtitleConversions)
        {
            var request = state.Request;

            var audioTranscodeParams = new List<string>();

            var bitrate = GetAudioBitrateParam(state);

            if (bitrate.HasValue)
            {
                audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(UsCulture));
            }

            var channels = GetNumAudioChannelsParam(request, state.AudioStream);

            if (channels.HasValue)
            {
                audioTranscodeParams.Add("-ac " + channels.Value);
            }
            
            if (request.AudioSampleRate.HasValue)
            {
                audioTranscodeParams.Add("-ar " + request.AudioSampleRate.Value);
            }

            const string vn = " -vn";

            return string.Format("{0} -i {1}{2} -threads 0{5} {3} -id3v2_version 3 -write_id3v1 1 \"{4}\"",
                GetFastSeekCommandLineParameter(request),
                GetInputArgument(state.Item, state.IsoMount),
                GetSlowSeekCommandLineParameter(request),
                string.Join(" ", audioTranscodeParams.ToArray()),
                outputPath,
                vn).Trim();
        }
Esempio n. 2
0
        /// <summary>
        /// Gets the audio arguments.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        protected override string GetAudioArguments(StreamState state)
        {
            var codec = GetAudioEncoder(state);

            if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
            {
                return "-codec:a:0 copy";
            }

            var args = "-codec:a:0 " + codec;

            var channels = state.OutputAudioChannels;

            if (channels.HasValue)
            {
                args += " -ac " + channels.Value;
            }

            var bitrate = state.OutputAudioBitrate;

            if (bitrate.HasValue)
            {
                args += " -ab " + bitrate.Value.ToString(UsCulture);
            }

            args += " " + GetAudioFilterParam(state, true);

            return args;
        }
Esempio n. 3
0
        /// <summary>
        /// Processes the request async.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>Task{System.Object}.</returns>
        public async Task<object> ProcessRequestAsync(StreamState state)
        {
            var playlist = GetOutputFilePath(state);
            var isPlaylistNewlyCreated = false;

            // If the playlist doesn't already exist, startup ffmpeg
            if (!File.Exists(playlist))
            {
                isPlaylistNewlyCreated = true;
                await StartFfMpeg(state, playlist).ConfigureAwait(false);
            }
            else
            {
                ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
            }

            // Get the current playlist text and convert to bytes
            var playlistText = await GetPlaylistFileText(playlist, isPlaylistNewlyCreated).ConfigureAwait(false);

            try
            {
                return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
            }
            finally
            {
                ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
            }
        }
Esempio n. 4
0
        protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
        {
            var audioTranscodeParams = new List<string>();

            var bitrate = state.OutputAudioBitrate;

            if (bitrate.HasValue)
            {
                audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(UsCulture));
            }

            if (state.OutputAudioChannels.HasValue)
            {
                audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture));
            }

            if (state.OutputAudioSampleRate.HasValue)
            {
                audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture));
            }

            const string vn = " -vn";

            var threads = GetNumberOfThreads(state, false);

            var inputModifier = GetInputModifier(state);

            return string.Format("{0} -i {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
                inputModifier,
                GetInputArgument(transcodingJobId, state),
                threads,
                vn,
                string.Join(" ", audioTranscodeParams.ToArray()),
                outputPath).Trim();
        }
Esempio n. 5
0
        public string GetManifestText(StreamState state, string playlistUrl)
        {
            var builder = new StringBuilder();

            var time = TimeSpan.FromTicks(state.RunTimeTicks.Value);

            var duration = "PT" + time.Hours.ToString("00", UsCulture) + "H" + time.Minutes.ToString("00", UsCulture) + "M" + time.Seconds.ToString("00", UsCulture) + ".00S";

            builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

            builder.AppendFormat(
                "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:mpeg:dash:schema:mpd:2011\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\" profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" type=\"static\" mediaPresentationDuration=\"{0}\" minBufferTime=\"PT5.0S\">",
                duration);

            builder.Append("<ProgramInformation>");
            builder.Append("</ProgramInformation>");

            builder.Append("<Period start=\"PT0S\">");
            builder.Append(GetVideoAdaptationSet(state, playlistUrl));
            builder.Append(GetAudioAdaptationSet(state, playlistUrl));
            builder.Append("</Period>");

            builder.Append("</MPD>");

            return builder.ToString();
        }
Esempio n. 6
0
  /////////////
  /// Public Methods
  ////////////
 
  /**
   * Implementing the interface from ITransferManager
   * When a request is allowed, we set up the state and
   * start acting
   */
  public Status Allow(Request req, System.IO.Stream data) {
 
    Status stat = new Status(req, data);
    lock( _sync ) { 
      _tid_to_status[req.LocalTID] = stat; 
    }

    if( req.Reqtype == Opcode.ReadReq ) {
      /**
       * We are starting a read request here.  We send the
       * first data packet as an ack of this request
       */
      StreamState rs = new StreamState();
      int new_block = 1;
      stat.StartBlock(new_block, rs);
      rs.Stat = stat;
      rs.Block = new_block;
      rs.Data = new byte[ stat.Request.Blksize ];
      rs.Offset = 0;
      stat.Data.BeginRead(rs.Data, rs.Offset, stat.Request.Blksize,
			  new AsyncCallback(this.ReadHandler),
			  rs);
    }
    else if( req.Reqtype == Opcode.WriteReq ) {
      SendAck(req, 0);
    }
    else {
      /**
       * This can't happen because we would only process Read or Write
       * requests
       * @todo add error handling if ReqType is non-sensical
       */
    }
    return stat;
  }
Esempio n. 7
0
        internal FlowState(Flow flow)
        {
            this.Tasks = new List<TaskState>();
            this.Art = flow.Art;

            foreach (var task in flow.Nodes)
            {
                TaskState state = new TaskState()
                {
                    ItemsProcessed = task.ItemsProcessed,
                    Name = task.Name,
                    Status = task.Status,
                    TotalSecondsBlocked = task.TotalSecondsBlocked,
                    TotalSecondsProcessing = task.TotalSecondsProcessing,
                    Position = task.Position
                };

                this.Tasks.Add(state);
            }
            this.Streams = new List<StreamState>();
            foreach (var stream in flow.Streams)
            {
                StreamState state = new StreamState()
                {
                    Name = stream.Name,
                    Closed = stream.IsClosed,
                    Count = stream.Count,
                    InPoint = stream.InPoint
                };
                this.Streams.Add(state);
            }
        }
Esempio n. 8
0
        private string GetVideoRepresentationOpenElement(StreamState state)
        {
            var codecs = GetVideoCodecDescriptor(state);

            var mime = "video/mp4";

            var xml = "<Representation id=\"0\" mimeType=\"" + mime + "\" codecs=\"" + codecs + "\"";

            if (state.OutputWidth.HasValue)
            {
                xml += " width=\"" + state.OutputWidth.Value.ToString(UsCulture) + "\"";
            }
            if (state.OutputHeight.HasValue)
            {
                xml += " height=\"" + state.OutputHeight.Value.ToString(UsCulture) + "\"";
            }
            if (state.OutputVideoBitrate.HasValue)
            {
                xml += " bandwidth=\"" + state.OutputVideoBitrate.Value.ToString(UsCulture) + "\"";
            }

            xml += ">";

            return xml;
        }
        /// <summary>
        /// Gets the audio arguments.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        protected override string GetAudioArguments(StreamState state)
        {
            var codec = GetAudioCodec(state.Request);

            var args = "-codec:a " + codec;

            var channels = GetNumAudioChannelsParam(state.Request, state.AudioStream);

            if (channels.HasValue)
            {
                args += " -ac " + channels.Value;
            }

            if (state.Request.AudioSampleRate.HasValue)
            {
                args += " -ar " + state.Request.AudioSampleRate.Value;
            }

            if (state.Request.AudioBitRate.HasValue)
            {
                args += " -ab " + state.Request.AudioBitRate.Value;
            }

            return args;
        }
        /// <summary>
        /// Gets the output file extension.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        protected override string GetOutputFileExtension(StreamState state)
        {
            var ext = base.GetOutputFileExtension(state);

            if (!string.IsNullOrEmpty(ext))
            {
                return ext;
            }

            var isVideoRequest = state.VideoRequest != null;

            // Try to infer based on the desired video codec
            if (isVideoRequest)
            {
                var videoCodec = state.VideoRequest.VideoCodec;

                if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
                {
                    return ".ts";
                }
                if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
                {
                    return ".ogv";
                }
                if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
                {
                    return ".webm";
                }
                if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
                {
                    return ".asf";
                }
            }

            // Try to infer based on the desired audio codec
            if (!isVideoRequest)
            {
                var audioCodec = state.Request.AudioCodec;

                if (string.Equals("aac", audioCodec, StringComparison.OrdinalIgnoreCase))
                {
                    return ".aac";
                }
                if (string.Equals("mp3", audioCodec, StringComparison.OrdinalIgnoreCase))
                {
                    return ".mp3";
                }
                if (string.Equals("vorbis", audioCodec, StringComparison.OrdinalIgnoreCase))
                {
                    return ".ogg";
                }
                if (string.Equals("wma", audioCodec, StringComparison.OrdinalIgnoreCase))
                {
                    return ".wma";
                }
            }

            return null;
        }
Esempio n. 11
0
        protected override string GetOutputFilePath(StreamState state)
        {
            var folder = ApplicationPaths.EncodedMediaCachePath;

            var outputFileExtension = GetOutputFileExtension(state);

            return Path.Combine(folder, GetCommandLineArguments("dummy\\dummy", state, false).GetMD5() + (outputFileExtension ?? string.Empty).ToLower());
        }
Esempio n. 12
0
        protected override string GetOutputFilePath(StreamState state)
        {
            var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;

            var outputFileExtension = GetOutputFileExtension(state);

            return Path.Combine(folder, GetCommandLineArguments("dummy\\dummy", state, false).GetMD5() + (outputFileExtension ?? string.Empty).ToLower());
        }
Esempio n. 13
0
        /// <summary>
        /// Processes the request async.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>Task{System.Object}.</returns>
        public async Task<object> ProcessRequestAsync(StreamState state)
        {
            if (!state.VideoRequest.VideoBitRate.HasValue && (!state.VideoRequest.VideoCodec.HasValue || state.VideoRequest.VideoCodec.Value != VideoCodecs.Copy))
            {
                throw new ArgumentException("A video bitrate is required");
            }
            if (!state.Request.AudioBitRate.HasValue && (!state.Request.AudioCodec.HasValue || state.Request.AudioCodec.Value != AudioCodecs.Copy))
            {
                throw new ArgumentException("An audio bitrate is required");
            }

            var playlist = GetOutputFilePath(state);
            var isPlaylistNewlyCreated = false;

            // If the playlist doesn't already exist, startup ffmpeg
            if (!File.Exists(playlist))
            {
                isPlaylistNewlyCreated = true;
                await StartFfMpeg(state, playlist).ConfigureAwait(false);
            }
            else
            {
                ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls);
            }

            if (isPlaylistNewlyCreated)
            {
                await WaitForMinimumSegmentCount(playlist, 3).ConfigureAwait(false);
            }

            int audioBitrate;
            int videoBitrate;
            GetPlaylistBitrates(state, out audioBitrate, out videoBitrate);

            var appendBaselineStream = false;
            var baselineStreamBitrate = 64000;

            var hlsVideoRequest = state.VideoRequest as GetHlsVideoStream;
            if (hlsVideoRequest != null)
            {
                appendBaselineStream = hlsVideoRequest.AppendBaselineStream;
                baselineStreamBitrate = hlsVideoRequest.BaselineStreamAudioBitRate ?? baselineStreamBitrate;
            }

            var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, appendBaselineStream, baselineStreamBitrate);

            try
            {
                return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
            }
            finally
            {
                ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls);
            }
        }
        /// <summary>
        /// Gets the output file extension.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        protected override string GetOutputFileExtension(StreamState state)
        {
            var ext = base.GetOutputFileExtension(state);

            if (!string.IsNullOrEmpty(ext))
            {
                return ext;
            }

            var videoRequest = state.Request as VideoStreamRequest;

            // Try to infer based on the desired video codec
            if (videoRequest != null && videoRequest.VideoCodec.HasValue)
            {
                var video = state.Item as Video;

                if (video != null)
                {
                    switch (videoRequest.VideoCodec.Value)
                    {
                        case VideoCodecs.H264:
                            return ".ts";
                        case VideoCodecs.Theora:
                            return ".ogv";
                        case VideoCodecs.Vpx:
                            return ".webm";
                        case VideoCodecs.Wmv:
                            return ".asf";
                    }
                }
            }

            // Try to infer based on the desired audio codec
            if (state.Request.AudioCodec.HasValue)
            {
                var audio = state.Item as Audio;

                if (audio != null)
                {
                    switch (state.Request.AudioCodec.Value)
                    {
                        case AudioCodecs.Aac:
                            return ".aac";
                        case AudioCodecs.Mp3:
                            return ".mp3";
                        case AudioCodecs.Vorbis:
                            return ".ogg";
                        case AudioCodecs.Wma:
                            return ".wma";
                    }
                }
            }

            return null;
        }
Esempio n. 15
0
 public UserStreamReceiver(ApiAccessor accessor, IStreamHandler handler)
 {
     _accessor = accessor;
     _handler = handler;
     ChangeState(StreamState.Disconnected);
     // set default values to parameters
     StallWarnings = true;
     StreamFilterLevel = StreamFilterLevel.None;
     _currentState = StreamState.Connected;
     _backoffMode = BackoffMode.None;
     _backoffWait = 0;
     _hardErrorCount = 0;
 }
Esempio n. 16
0
        private string GetVideoAdaptationSet(StreamState state, string playlistUrl)
        {
            var builder = new StringBuilder();

            builder.Append("<AdaptationSet id=\"video\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">");
            builder.Append(GetVideoRepresentationOpenElement(state));

            AppendSegmentList(state, builder, "0", playlistUrl);

            builder.Append("</Representation>");
            builder.Append("</AdaptationSet>");

            return builder.ToString();
        }
Esempio n. 17
0
        /// <summary>
        /// Gets the audio arguments.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        protected override string GetAudioArguments(StreamState state)
        {
            var codec = GetAudioCodec(state.Request);

            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
            {
                return "-codec:a:0 copy";
            }

            var args = "-codec:a:0 " + codec;

            if (state.AudioStream != null)
            {
                var channels = GetNumAudioChannelsParam(state.Request, state.AudioStream);

                if (channels.HasValue)
                {
                    args += " -ac " + channels.Value;
                }

                var bitrate = GetAudioBitrateParam(state);

                if (bitrate.HasValue)
                {
                    args += " -ab " + bitrate.Value.ToString(UsCulture);
                }

                var volParam = string.Empty;
                var audioSampleRate = string.Empty;

                // Boost volume to 200% when downsampling from 6ch to 2ch
                if (channels.HasValue && channels.Value <= 2 && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5)
                {
                    volParam = ",volume=2.000000";
                }

                if (state.Request.AudioSampleRate.HasValue)
                {
                    audioSampleRate = state.Request.AudioSampleRate.Value + ":";
                }

                args += string.Format(" -af \"adelay=1,aresample={0}async=1000{1}\"", audioSampleRate, volParam);

                return args;
            }

            return args;
        }
Esempio n. 18
0
        private string GetAudioAdaptationSet(StreamState state, string playlistUrl)
        {
            var builder = new StringBuilder();

            builder.Append("<AdaptationSet id=\"audio\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">");
            builder.Append(GetAudioRepresentationOpenElement(state));

            builder.Append("<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"6\" />");

            AppendSegmentList(state, builder, "1", playlistUrl);

            builder.Append("</Representation>");
            builder.Append("</AdaptationSet>");

            return builder.ToString();
        }
Esempio n. 19
0
        /// <summary>
        /// Gets the video arguments.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        protected override string GetVideoArguments(StreamState state)
        {
            var codec = GetVideoEncoder(state);

            var args = "-codec:v:0 " + codec;

            if (state.EnableMpegtsM2TsMode)
            {
                args += " -mpegts_m2ts_mode 1";
            }

            // See if we can save come cpu cycles by avoiding encoding
            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
            {
                // if h264_mp4toannexb is ever added, do not use it for live tv
                if (state.VideoStream != null && IsH264(state.VideoStream) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
                {
                    args += " -bsf:v h264_mp4toannexb";
                }
                return args;
            }

            var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
                state.SegmentLength.ToString(UsCulture));

            var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.VideoRequest.SubtitleMethod == SubtitleDeliveryMethod.Encode;

            args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg;

            // Add resolution params, if specified
            if (!hasGraphicalSubs)
            {
                args += GetOutputSizeParam(state, codec);
            }

            // This is for internal graphical subs
            if (hasGraphicalSubs)
            {
                args += GetGraphicalSubtitleParam(state, codec);
            }

            args += " -flags -global_header";

            return args;
        }
Esempio n. 20
0
        public OpusStreamConvertor(string fileName, Options options)
        {
            _fileName = fileName + ".opus";
            _options = options;
            _streamState = new StreamState(options);

            if (File.Exists(_fileName))
            {
                SetGranulePos(_streamState);
            }
            else
            {
                using (var fs = new FileStream(_fileName, FileMode.Create, FileAccess.Write, FileShare.Read))
                {
                    SetHeader(_streamState, fs);
                    SetComment(_streamState, fs);
                }
            }
        }
Esempio n. 21
0
        private void SetComment(StreamState os, Stream stream)
        {
            var opusTags = new OpusTags();
            opusTags.Add("ENCODER", "opusenc from libopus 1.0.1-21-gff16ab0");
            opusTags.AddOption(_options.BitRate);
            opusTags.AddOption(_options.BitRateEncoding);
            opusTags.AddOption("ignorelength", string.Empty);

            opusTags.Pad();

            var opComment = new Packet
            {
                PacketData = opusTags.GetPacked(),
                PacketDataLength = opusTags.GetPackedLength(),
                Bos = 0,
                Eos = 0,
                GranulePos = 0
            };
            os.AddWaveData(opComment);
            os.Flush(stream);
        }
Esempio n. 22
0
        /// <summary>
        /// Gets the video arguments.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        protected override string GetVideoArguments(StreamState state)
        {
            var codec = GetVideoEncoder(state);

            var args = "-codec:v:0 " + codec;

            if (state.EnableMpegtsM2TsMode)
            {
                args += " -mpegts_m2ts_mode 1";
            }

            // See if we can save come cpu cycles by avoiding encoding
            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
            {
                return state.VideoStream != null && IsH264(state.VideoStream) ?
                    args + " -bsf:v h264_mp4toannexb" :
                    args;
            }
            
            var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
                state.SegmentLength.ToString(UsCulture));

            var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;

            args += " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;

            // Add resolution params, if specified
            if (!hasGraphicalSubs)
            {
                args += GetOutputSizeParam(state, codec);
            }

            // This is for internal graphical subs
            if (hasGraphicalSubs)
            {
                args += GetGraphicalSubtitleParam(state, codec);
            }

            return args;
        }
Esempio n. 23
0
        protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
        {
            var audioTranscodeParams = new List<string>();

            var bitrate = state.OutputAudioBitrate;

            if (bitrate.HasValue)
            {
                audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(UsCulture));
            }

            if (state.OutputAudioChannels.HasValue)
            {
                audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture));
            }

            // opus will fail on 44100
            if (!string.Equals(state.OutputAudioCodec, "opus", global::System.StringComparison.OrdinalIgnoreCase))
            {
                if (state.OutputAudioSampleRate.HasValue)
                {
                    audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture));
                }
            }

            const string vn = " -vn";

            var threads = GetNumberOfThreads(state, false);

            var inputModifier = GetInputModifier(state);

            return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
                inputModifier,
                GetInputArgument(state),
                threads,
                vn,
                string.Join(" ", audioTranscodeParams.ToArray()),
                outputPath).Trim();
        }
Esempio n. 24
0
        /// <summary>
        /// Gets the command line arguments.
        /// </summary>
        /// <param name="outputPath">The output path.</param>
        /// <param name="state">The state.</param>
        /// <param name="performSubtitleConversions">if set to <c>true</c> [perform subtitle conversions].</param>
        /// <returns>System.String.</returns>
        /// <exception cref="System.InvalidOperationException">Only aac and mp3 audio codecs are supported.</exception>
        protected override string GetCommandLineArguments(string outputPath, StreamState state, bool performSubtitleConversions)
        {
            var request = state.Request;

            var audioTranscodeParams = new List<string>();

            if (string.Equals(Path.GetExtension(outputPath), ".aac", StringComparison.OrdinalIgnoreCase))
            {
                audioTranscodeParams.Add("-strict experimental");
            }

            if (request.AudioBitRate.HasValue)
            {
                audioTranscodeParams.Add("-ab " + request.AudioBitRate.Value);
            }

            var channels = GetNumAudioChannelsParam(request, state.AudioStream);

            if (channels.HasValue)
            {
                audioTranscodeParams.Add("-ac " + channels.Value);
            }

            if (request.AudioSampleRate.HasValue)
            {
                audioTranscodeParams.Add("-ar " + request.AudioSampleRate.Value);
            }

            const string vn = " -vn";

            return string.Format("{0} -i {1}{2} -threads 0{5} {3} -id3v2_version 3 -write_id3v1 1 \"{4}\"",
                GetFastSeekCommandLineParameter(request),
                GetInputArgument(state.Item, state.IsoMount),
                GetSlowSeekCommandLineParameter(request),
                string.Join(" ", audioTranscodeParams.ToArray()),
                outputPath,
                vn).Trim();
        }
Esempio n. 25
0
        /// <summary>
        /// Gets the output file extension.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        private static string?GetOutputFileExtension(StreamState state)
        {
            var ext = Path.GetExtension(state.RequestedUrl);

            if (!string.IsNullOrEmpty(ext))
            {
                return(ext);
            }

            // Try to infer based on the desired video codec
            if (state.IsVideoRequest)
            {
                var videoCodec = state.Request.VideoCodec;

                if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase) ||
                    string.Equals(videoCodec, "h265", StringComparison.OrdinalIgnoreCase))
                {
                    return(".ts");
                }

                if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
                {
                    return(".ogv");
                }

                if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
                {
                    return(".webm");
                }

                if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
                {
                    return(".asf");
                }
            }

            // Try to infer based on the desired audio codec
            if (!state.IsVideoRequest)
            {
                var audioCodec = state.Request.AudioCodec;

                if (string.Equals("aac", audioCodec, StringComparison.OrdinalIgnoreCase))
                {
                    return(".aac");
                }

                if (string.Equals("mp3", audioCodec, StringComparison.OrdinalIgnoreCase))
                {
                    return(".mp3");
                }

                if (string.Equals("vorbis", audioCodec, StringComparison.OrdinalIgnoreCase))
                {
                    return(".ogg");
                }

                if (string.Equals("wma", audioCodec, StringComparison.OrdinalIgnoreCase))
                {
                    return(".wma");
                }
            }

            return(null);
        }
Esempio n. 26
0
        /// <summary>
        /// Gets the audio arguments for transcoding.
        /// </summary>
        /// <param name="state">The <see cref="StreamState"/>.</param>
        /// <returns>The command line arguments for audio transcoding.</returns>
        private string GetAudioArguments(StreamState state)
        {
            if (state.AudioStream == null)
            {
                return(string.Empty);
            }

            var audioCodec = _encodingHelper.GetAudioEncoder(state);

            if (!state.IsOutputVideo)
            {
                if (EncodingHelper.IsCopyCodec(audioCodec))
                {
                    var bitStreamArgs = EncodingHelper.GetAudioBitStreamArguments(state, state.Request.SegmentContainer, state.MediaSource.Container);

                    return("-acodec copy -strict -2" + bitStreamArgs);
                }

                var audioTranscodeParams = string.Empty;

                audioTranscodeParams += "-acodec " + audioCodec;

                if (state.OutputAudioBitrate.HasValue)
                {
                    audioTranscodeParams += " -ab " + state.OutputAudioBitrate.Value.ToString(CultureInfo.InvariantCulture);
                }

                if (state.OutputAudioChannels.HasValue)
                {
                    audioTranscodeParams += " -ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture);
                }

                if (state.OutputAudioSampleRate.HasValue)
                {
                    audioTranscodeParams += " -ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture);
                }

                audioTranscodeParams += " -vn";
                return(audioTranscodeParams);
            }

            if (EncodingHelper.IsCopyCodec(audioCodec))
            {
                var bitStreamArgs = EncodingHelper.GetAudioBitStreamArguments(state, state.Request.SegmentContainer, state.MediaSource.Container);

                return("-acodec copy -strict -2" + bitStreamArgs);
            }

            var args = "-codec:a:0 " + audioCodec;

            var channels = state.OutputAudioChannels;

            if (channels.HasValue)
            {
                args += " -ac " + channels.Value;
            }

            var bitrate = state.OutputAudioBitrate;

            if (bitrate.HasValue)
            {
                args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture);
            }

            if (state.OutputAudioSampleRate.HasValue)
            {
                args += " -ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture);
            }

            args += _encodingHelper.GetAudioFilterParam(state, _encodingOptions, true);

            return(args);
        }
Esempio n. 27
0
        public bool Proccess(ref ServerAsyncEventArgs e, out bool closeConnection)
        {
            //  ----------------------------------------------------------
            //  |           | 0  | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  |
            //  ----------------------------------------------------------
            //  |         e | H  | HC |    |    |    |    |    |    |    |
            //  |        e1 |    |    | H  | HC | H  | H  |    |    |    |
            //  |   Buffer1 |    |    |    |    |  C |    | H  | HC | H  |
            //  |   Buffer2 |    |    |    |    |    |  C |    |    |  C |
            //  ----------------------------------------------------------

            closeConnection = false;

            switch (state)
            {
            case StreamState.WaitingHeaders:
            {
                int oldBytesProccessed = bytesProccessed;

                var data = new ArraySegment <byte>(e.Buffer, e.Offset + bytesProccessed, e.BytesTransferred - bytesProccessed);

                PreProcessRaw(data);
                var result = Parse(data);

                switch (result.ParseCode)
                {
                case ParseCode.NotEnoughData:
                {
                    bytesProccessed += data.Count;

                    ResetParser(ResetReason.NotEnoughData);

                    Buffer1.Resize(MaximumHeadersSize);
                    Buffer1.CopyTransferredFrom(e, oldBytesProccessed);
                    state = StreamState.WaitingHeadersContinue;
                }
                break;

                case ParseCode.Error:
                {
                    closeConnection = true;
                }
                break;

                case ParseCode.Skip:
                {
                    bytesProccessed += result.Count;
                }
                break;

                case ParseCode.HeaderDone:
                {
                    bytesProccessed += result.HeaderLength;

                    SetReaderStorage(Storage.E, e.Buffer, e.Offset + oldBytesProccessed, result.HeaderLength);

                    expectedContentLength = result.ContentLength;

                    if (expectedContentLength <= 0)
                    {
                        SetReady();
                    }
                    else
                    {
                        int bytesLeft = e.BytesTransferred - bytesProccessed;

                        if (bytesLeft >= expectedContentLength)
                        {
                            SetReady(Storage.E, e.Buffer, e.Offset + bytesProccessed, expectedContentLength);
                            bytesProccessed += expectedContentLength;
                        }
                        else
                        {
                            if (expectedContentLength <= e.Count - e.BytesTransferred)
                            {
                                state = StreamState.WaitingMicroBody;
                            }
                            else if (expectedContentLength < MaximumHeadersSize)
                            {
                                if (Buffer1.IsInvalid || Buffer1.Capacity < expectedContentLength)
                                {
                                    if (Buffer1.Resize(Math.Max(expectedContentLength, MinimumBuffer1Size)) == false)
                                    {
                                        closeConnection = true;
                                    }
                                }

                                if (closeConnection == false)
                                {
                                    Buffer1.CopyTransferredFrom(e, bytesProccessed);
                                    state = StreamState.WaitingSmallBody;
                                }
                            }
                            else
                            {
                                if (Buffer2.Resize(expectedContentLength) == false)
                                {
                                    closeConnection = true;
                                }
                                else
                                {
                                    Buffer2.CopyTransferredFrom(e, bytesProccessed);
                                    state = StreamState.WaitingBigBody;
                                }
                            }

                            if (closeConnection == false)
                            {
                                e1            = e;
                                e             = null;
                                readerStorage = Storage.E1;
                            }

                            bytesProccessed       += bytesLeft;
                            receivedContentLength += bytesLeft;
                        }
                    }
                }
                break;
                }
            }
            break;

            case StreamState.WaitingHeadersContinue:
            {
                int count = Math.Min(e.BytesTransferred - bytesProccessed, Buffer1.FreeSize);

                PreProcessRaw(new ArraySegment <byte>(e.Buffer, e.Offset, e.BytesTransferred - bytesProccessed));

                System.Buffer.BlockCopy(e.Buffer, e.Offset, Buffer1.Array, Buffer1.Offset + Buffer1.Count, count);

                var data   = new ArraySegment <byte>(Buffer1.Array, Buffer1.Offset, Buffer1.Count + count);
                var result = Parse(data);

                switch (result.ParseCode)
                {
                case ParseCode.NotEnoughData:
                {
                    ResetParser(ResetReason.NotEnoughData);

                    if (data.Count < Buffer1.Capacity)
                    {
                        Buffer1.AddCount(count);
                        bytesProccessed += count;
                    }
                    else
                    {
                        closeConnection = true;
                    }
                }
                break;

                case ParseCode.Error:
                {
                    closeConnection = true;
                }
                break;

                case ParseCode.Skip:
                    throw new NotImplementedException();

                case ParseCode.HeaderDone:
                {
                    int delta = result.HeaderLength - Buffer1.Count;
                    Buffer1.AddCount(delta);
                    bytesProccessed += delta;

                    SetReaderStorage(Storage.Buffer1, Buffer1.Array, Buffer1.Offset, result.HeaderLength);

                    expectedContentLength = result.ContentLength;

                    if (expectedContentLength <= 0)
                    {
                        SetReady();
                    }
                    else
                    {
                        int bytesLeft = e.BytesTransferred - bytesProccessed;

                        if (bytesLeft >= expectedContentLength)
                        {
                            SetReady(Storage.E, e.Buffer, e.Offset + bytesProccessed, expectedContentLength);
                            bytesProccessed += expectedContentLength;
                        }
                        else
                        {
                            if (expectedContentLength < Buffer1.FreeSize)
                            {
                                Buffer1.AddCount(bytesLeft);
                                state = StreamState.WaitingSmallBody;
                            }
                            else
                            {
                                if (Buffer2.Resize(expectedContentLength) == false)
                                {
                                    closeConnection = true;
                                }
                                Buffer2.CopyTransferredFrom(e, bytesProccessed);
                                state = StreamState.WaitingBigBody;
                            }

                            bytesProccessed       += bytesLeft;
                            receivedContentLength += bytesLeft;
                        }
                    }
                }
                break;
                }
            }
            break;

            case StreamState.WaitingMicroBody:
            {
                int count = Math.Min(e.BytesTransferred - bytesProccessed,
                                     expectedContentLength - receivedContentLength);

                var data = new ArraySegment <byte>(e.Buffer, e.Offset + bytesProccessed, count);

                PreProcessRaw(data);
                System.Buffer.BlockCopy(data.Array, data.Offset, e1.Buffer, e1.Offset + e1.BytesTransferred, data.Count);

                //System.Buffer.BlockCopy(e.Buffer, e.Offset + bytesProccessed,
                //    e1.Buffer, e1.Offset + e1.BytesTransferred, count);

                e1.BytesTransferred += count;

                receivedContentLength += count;
                bytesProccessed       += count;

                if (receivedContentLength == expectedContentLength)
                {
                    SetReady(Storage.E1, e1.Buffer, e1.Offset + e1.BytesTransferred - receivedContentLength, receivedContentLength);
                }
            }
            break;

            case StreamState.WaitingSmallBody:
            {
                int count = Math.Min(e.BytesTransferred - bytesProccessed,
                                     expectedContentLength - receivedContentLength);

                var data = new ArraySegment <byte>(e.Buffer, e.Offset + bytesProccessed, count);

                PreProcessRaw(data);
                Buffer1.CopyFrom(data);
                //Buffer1.CopyFrom(e.Buffer, e.Offset + bytesProccessed, count);

                receivedContentLength += count;
                bytesProccessed       += count;

                if (receivedContentLength == expectedContentLength)
                {
                    SetReady(Storage.Buffer1, Buffer1.Array, Buffer1.Offset + Buffer1.Count - receivedContentLength, receivedContentLength);
                }
            }
            break;

            case StreamState.WaitingBigBody:
            {
                int count = Math.Min(e.BytesTransferred - bytesProccessed,
                                     expectedContentLength - receivedContentLength);

                var data = new ArraySegment <byte>(e.Buffer, e.Offset + bytesProccessed, count);

                PreProcessRaw(data);
                Buffer2.CopyFrom(data);
                //Buffer2.CopyFrom(e.Buffer, e.Offset + bytesProccessed, count);

                receivedContentLength += count;
                bytesProccessed       += count;

                if (receivedContentLength == expectedContentLength)
                {
                    SetReady(Storage.Buffer2, Buffer2.Array, Buffer2.Offset + Buffer2.Count - receivedContentLength, receivedContentLength);
                }
            }
            break;
            }

            bool continueProccessing = closeConnection == false &&
                                       e != null && bytesProccessed < e.BytesTransferred;

            if (continueProccessing == false)
            {
                bytesProccessed = 0;
            }

            return(continueProccessing);
        }
Esempio n. 28
0
 public HeaderContentConnection()
 {
     state = StreamState.WaitingHeaders;
 }
Esempio n. 29
0
        /// <summary>
        /// Gets the stream result.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
        /// <param name="cancellationTokenSource">The cancellation token source.</param>
        /// <returns>Task{System.Object}.</returns>
        private async Task <object> GetStreamResult(StreamState state, IDictionary <string, string> responseHeaders, bool isHeadRequest, CancellationTokenSource cancellationTokenSource)
        {
            // Use the command line args with a dummy playlist path
            var outputPath = state.OutputFilePath;

            responseHeaders["Accept-Ranges"] = "none";

            var contentType = state.GetMimeType(outputPath);

            // TODO: The isHeadRequest is only here because ServiceStack will add Content-Length=0 to the response
            // What we really want to do is hunt that down and remove that
            var contentLength = state.EstimateContentLength || isHeadRequest?GetEstimatedContentLength(state) : null;

            if (contentLength.HasValue)
            {
                responseHeaders["Content-Length"] = contentLength.Value.ToString(UsCulture);
            }

            // Headers only
            if (isHeadRequest)
            {
                var streamResult = ResultFactory.GetResult(new byte[] { }, contentType, responseHeaders);

                var hasHeaders = streamResult as IHasHeaders;
                if (hasHeaders != null)
                {
                    if (contentLength.HasValue)
                    {
                        hasHeaders.Headers["Content-Length"] = contentLength.Value.ToString(CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        if (hasHeaders.Headers.ContainsKey("Content-Length"))
                        {
                            hasHeaders.Headers.Remove("Content-Length");
                        }
                    }
                }

                return(streamResult);
            }

            var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(outputPath);
            await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);

            try
            {
                TranscodingJob job;

                if (!FileSystem.FileExists(outputPath))
                {
                    job = await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false);
                }
                else
                {
                    job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
                    state.Dispose();
                }

                var outputHeaders = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

                outputHeaders["Content-Type"] = contentType;

                // Add the response headers to the result object
                foreach (var item in responseHeaders)
                {
                    outputHeaders[item.Key] = item.Value;
                }

                return(new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, CancellationToken.None));
            }
            finally
            {
                transcodingLock.Release();
            }
        }
Esempio n. 30
0
        private async Task <object> GetSegmentResult(StreamState state, string playlistPath,
                                                     string segmentPath,
                                                     int segmentIndex,
                                                     TranscodingJob transcodingJob,
                                                     CancellationToken cancellationToken)
        {
            // If all transcoding has completed, just return immediately
            if (transcodingJob != null && transcodingJob.HasExited && File.Exists(segmentPath))
            {
                return(GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob));
            }

            var segmentFilename = Path.GetFileName(segmentPath);

            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    using (var fileStream = GetPlaylistFileStream(playlistPath))
                    {
                        using (var reader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize))
                        {
                            var text = await reader.ReadToEndAsync().ConfigureAwait(false);

                            // If it appears in the playlist, it's done
                            if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
                            {
                                if (File.Exists(segmentPath))
                                {
                                    return(GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob));
                                }
                                //break;
                            }
                        }
                    }
                }
                catch (IOException)
                {
                    // May get an error if the file is locked
                }

                await Task.Delay(100, cancellationToken).ConfigureAwait(false);
            }

            // if a different file is encoding, it's done
            //var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath);
            //if (currentTranscodingIndex > segmentIndex)
            //{
            //return GetSegmentResult(segmentPath, segmentIndex);
            //}

            //// Wait for the file to stop being written to, then stream it
            //var length = new FileInfo(segmentPath).Length;
            //var eofCount = 0;

            //while (eofCount < 10)
            //{
            //    var info = new FileInfo(segmentPath);

            //    if (!info.Exists)
            //    {
            //        break;
            //    }

            //    var newLength = info.Length;

            //    if (newLength == length)
            //    {
            //        eofCount++;
            //    }
            //    else
            //    {
            //        eofCount = 0;
            //    }

            //    length = newLength;
            //    await Task.Delay(100, cancellationToken).ConfigureAwait(false);
            //}

            cancellationToken.ThrowIfCancellationRequested();
            return(GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob));
        }
Esempio n. 31
0
 protected override bool EnableThrottling(StreamState state)
 {
     return(true);
 }
Esempio n. 32
0
        /// <summary>
        /// Gets the current streaming state.
        /// </summary>
        /// <param name="streamingRequest">The <see cref="StreamingRequestDto"/>.</param>
        /// <param name="httpRequest">The <see cref="HttpRequest"/>.</param>
        /// <param name="authorizationContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
        /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
        /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
        /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
        /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
        /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
        /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
        /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param>
        /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param>
        /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
        /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param>
        /// <param name="transcodingJobHelper">Initialized <see cref="TranscodingJobHelper"/>.</param>
        /// <param name="transcodingJobType">The <see cref="TranscodingJobType"/>.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
        /// <returns>A <see cref="Task"/> containing the current <see cref="StreamState"/>.</returns>
        public static async Task <StreamState> GetStreamingState(
            StreamingRequestDto streamingRequest,
            HttpRequest httpRequest,
            IAuthorizationContext authorizationContext,
            IMediaSourceManager mediaSourceManager,
            IUserManager userManager,
            ILibraryManager libraryManager,
            IServerConfigurationManager serverConfigurationManager,
            IMediaEncoder mediaEncoder,
            IFileSystem fileSystem,
            ISubtitleEncoder subtitleEncoder,
            IConfiguration configuration,
            IDlnaManager dlnaManager,
            IDeviceManager deviceManager,
            TranscodingJobHelper transcodingJobHelper,
            TranscodingJobType transcodingJobType,
            CancellationToken cancellationToken)
        {
            EncodingHelper encodingHelper = new EncodingHelper(mediaEncoder, fileSystem, subtitleEncoder, configuration);

            // Parse the DLNA time seek header
            if (!streamingRequest.StartTimeTicks.HasValue)
            {
                var timeSeek = httpRequest.Headers["TimeSeekRange.dlna.org"];

                streamingRequest.StartTimeTicks = ParseTimeSeekHeader(timeSeek.ToString());
            }

            if (!string.IsNullOrWhiteSpace(streamingRequest.Params))
            {
                ParseParams(streamingRequest);
            }

            streamingRequest.StreamOptions = ParseStreamOptions(httpRequest.Query);

            var url = httpRequest.Path.Value.Split('.').Last();

            if (string.IsNullOrEmpty(streamingRequest.AudioCodec))
            {
                streamingRequest.AudioCodec = encodingHelper.InferAudioCodec(url);
            }

            var enableDlnaHeaders = !string.IsNullOrWhiteSpace(streamingRequest.Params) ||
                                    streamingRequest.StreamOptions.ContainsKey("dlnaheaders") ||
                                    string.Equals(httpRequest.Headers["GetContentFeatures.DLNA.ORG"], "1", StringComparison.OrdinalIgnoreCase);

            var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper)
            {
                Request           = streamingRequest,
                RequestedUrl      = url,
                UserAgent         = httpRequest.Headers[HeaderNames.UserAgent],
                EnableDlnaHeaders = enableDlnaHeaders
            };

            var auth = authorizationContext.GetAuthorizationInfo(httpRequest);

            if (!auth.UserId.Equals(Guid.Empty))
            {
                state.User = userManager.GetUserById(auth.UserId);
            }

            if (state.IsVideoRequest && !string.IsNullOrWhiteSpace(state.Request.VideoCodec))
            {
                state.SupportedVideoCodecs = state.Request.VideoCodec.Split(',', StringSplitOptions.RemoveEmptyEntries);
                state.Request.VideoCodec   = state.SupportedVideoCodecs.FirstOrDefault();
            }

            if (!string.IsNullOrWhiteSpace(streamingRequest.AudioCodec))
            {
                state.SupportedAudioCodecs = streamingRequest.AudioCodec.Split(',', StringSplitOptions.RemoveEmptyEntries);
                state.Request.AudioCodec   = state.SupportedAudioCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToAudioCodec(i))
                                             ?? state.SupportedAudioCodecs.FirstOrDefault();
            }

            if (!string.IsNullOrWhiteSpace(streamingRequest.SubtitleCodec))
            {
                state.SupportedSubtitleCodecs = streamingRequest.SubtitleCodec.Split(',', StringSplitOptions.RemoveEmptyEntries);
                state.Request.SubtitleCodec   = state.SupportedSubtitleCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToSubtitleCodec(i))
                                                ?? state.SupportedSubtitleCodecs.FirstOrDefault();
            }

            var item = libraryManager.GetItemById(streamingRequest.Id);

            state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);

            MediaSourceInfo?mediaSource = null;

            if (string.IsNullOrWhiteSpace(streamingRequest.LiveStreamId))
            {
                var currentJob = !string.IsNullOrWhiteSpace(streamingRequest.PlaySessionId)
                    ? transcodingJobHelper.GetTranscodingJob(streamingRequest.PlaySessionId)
                    : null;

                if (currentJob != null)
                {
                    mediaSource = currentJob.MediaSource;
                }

                if (mediaSource == null)
                {
                    var mediaSources = await mediaSourceManager.GetPlaybackMediaSources(libraryManager.GetItemById(streamingRequest.Id), null, false, false, cancellationToken).ConfigureAwait(false);

                    mediaSource = string.IsNullOrEmpty(streamingRequest.MediaSourceId)
                        ? mediaSources[0]
                        : mediaSources.Find(i => string.Equals(i.Id, streamingRequest.MediaSourceId, StringComparison.InvariantCulture));

                    if (mediaSource == null && Guid.Parse(streamingRequest.MediaSourceId) == streamingRequest.Id)
                    {
                        mediaSource = mediaSources[0];
                    }
                }
            }
            else
            {
                var liveStreamInfo = await mediaSourceManager.GetLiveStreamWithDirectStreamProvider(streamingRequest.LiveStreamId, cancellationToken).ConfigureAwait(false);

                mediaSource = liveStreamInfo.Item1;
                state.DirectStreamProvider = liveStreamInfo.Item2;
            }

            encodingHelper.AttachMediaSourceInfo(state, mediaSource, url);

            string?containerInternal = Path.GetExtension(state.RequestedUrl);

            if (string.IsNullOrEmpty(streamingRequest.Container))
            {
                containerInternal = streamingRequest.Container;
            }

            if (string.IsNullOrEmpty(containerInternal))
            {
                containerInternal = streamingRequest.Static ?
                                    StreamBuilder.NormalizeMediaSourceFormatIntoSingleContainer(state.InputContainer, state.MediaPath, null, DlnaProfileType.Audio)
                    : GetOutputFileExtension(state);
            }

            state.OutputContainer = (containerInternal ?? string.Empty).TrimStart('.');

            state.OutputAudioBitrate = encodingHelper.GetAudioBitrateParam(streamingRequest.AudioBitRate, state.AudioStream);

            state.OutputAudioCodec = streamingRequest.AudioCodec;

            state.OutputAudioChannels = encodingHelper.GetNumAudioChannelsParam(state, state.AudioStream, state.OutputAudioCodec);

            if (state.VideoRequest != null)
            {
                state.OutputVideoCodec   = state.Request.VideoCodec;
                state.OutputVideoBitrate = encodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);

                encodingHelper.TryStreamCopy(state);

                if (state.OutputVideoBitrate.HasValue && !EncodingHelper.IsCopyCodec(state.OutputVideoCodec))
                {
                    var resolution = ResolutionNormalizer.Normalize(
                        state.VideoStream?.BitRate,
                        state.VideoStream?.Width,
                        state.VideoStream?.Height,
                        state.OutputVideoBitrate.Value,
                        state.VideoStream?.Codec,
                        state.OutputVideoCodec,
                        state.VideoRequest.MaxWidth,
                        state.VideoRequest.MaxHeight);

                    state.VideoRequest.MaxWidth  = resolution.MaxWidth;
                    state.VideoRequest.MaxHeight = resolution.MaxHeight;
                }
            }

            ApplyDeviceProfileSettings(state, dlnaManager, deviceManager, httpRequest, streamingRequest.DeviceProfileId, streamingRequest.Static);

            var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
                ? GetOutputFileExtension(state)
                : ('.' + state.OutputContainer);

            state.OutputFilePath = GetOutputFilePath(state, ext !, serverConfigurationManager, streamingRequest.DeviceId, streamingRequest.PlaySessionId);

            return(state);
        }
Esempio n. 33
0
 protected override bool EnableThrottling(StreamState state)
 {
     return true;
 }
Esempio n. 34
0
 private bool EnableCopyTs(StreamState state)
 {
     return state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream;
 }
Esempio n. 35
0
        protected override string GetAudioArguments(StreamState state)
        {
            var codec = GetAudioEncoder(state);

            if (!state.IsOutputVideo)
            {
                if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
                {
                    return "-acodec copy";
                }

                var audioTranscodeParams = new List<string>();

                audioTranscodeParams.Add("-acodec " + codec);

                if (state.OutputAudioBitrate.HasValue)
                {
                    audioTranscodeParams.Add("-ab " + state.OutputAudioBitrate.Value.ToString(UsCulture));
                }

                if (state.OutputAudioChannels.HasValue)
                {
                    audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture));
                }

                if (state.OutputAudioSampleRate.HasValue)
                {
                    audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture));
                }

                audioTranscodeParams.Add("-vn");
                return string.Join(" ", audioTranscodeParams.ToArray());
            }

            if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
            {
                return "-codec:a:0 copy";
            }

            var args = "-codec:a:0 " + codec;

            var channels = state.OutputAudioChannels;

            if (channels.HasValue)
            {
                args += " -ac " + channels.Value;
            }

            var bitrate = state.OutputAudioBitrate;

            if (bitrate.HasValue)
            {
                args += " -ab " + bitrate.Value.ToString(UsCulture);
            }

            args += " " + GetAudioFilterParam(state, true);

            return args;
        }
Esempio n. 36
0
        /// <summary>
        /// Groups packets together into box packets as necessary
        /// </summary>
        public ICollection <ReliableInfo> boxReliablePackets(Queue <ReliableInfo> packetQueue, StreamState stream, int streamID)
        {               //Empty?
            if (packetQueue.Count == 0)
            {
                return(null);
            }
            //If it's just one packet, there's no need
            else if (packetQueue.Count == 1)
            {                   //We need to put it in a reliable case
                Reliable     reli  = new Reliable();
                ReliableInfo rinfo = packetQueue.Dequeue();

                reli.streamID = streamID;
                reli.packet   = rinfo.packet;
                rinfo.rid     = reli.rNumber = stream.S2C_Reliable++;
                rinfo.packet  = reli;

                List <ReliableInfo> list = new List <ReliableInfo>();
                list.Add(rinfo);
                return(list);
            }

            //Go through the list, creating boxed packets as we go
            List <ReliableInfo> reliables = new List <ReliableInfo>();
            ReliableInfo        info;
            ReliableBox         box = new ReliableBox(streamID);
            int packetStartSize     = 4 /*reliable*/ + 2 /*reliable box*/ + _CRCLength;
            int currentSize         = packetStartSize;                  //Header+footer size of a boxed reliable packet

            //Group our normal packets
            while (packetQueue.Count > 0 && packetQueue.Peek().dataStream == null)
            {
                ReliableInfo pInfo = packetQueue.Dequeue();

                //If the packet exceeds the max limit, send it on it's own
                if (2 + 1 + pInfo.packet.Length > byte.MaxValue)
                {                       //We need to send the previous boxing packets first, as they
                                        //should be in order of reliable id
                    if (box.reliables.Count > 0)
                    {
                        info     = new ReliableInfo();
                        info.rid = stream.S2C_Reliable++;

                        //Don't add a lonely box
                        if (box.reliables.Count == 1)
                        {
                            info.packet = new Reliable(box.reliables[0].packet, info.rid, streamID);
                        }
                        else
                        {                               //Make sure the box is serialized
                            box.MakeSerialized(this, _handler);

                            info.packet = new Reliable(box, info.rid, streamID);
                        }

                        info.consolidateEvents(box.reliables);

                        reliables.Add(info);
                    }

                    box         = new ReliableBox(streamID);
                    currentSize = packetStartSize;

                    //Add the packet on it's own
                    Reliable reli = new Reliable();

                    reli.streamID = streamID;
                    reli.packet   = pInfo.packet;
                    pInfo.rid     = reli.rNumber = stream.S2C_Reliable++;
                    pInfo.packet  = reli;

                    reliables.Add(pInfo);
                    continue;
                }

                //Do we have space to add this packet?
                if (currentSize + pInfo.packet.Length + 1 > udpMaxSize)
                {                       //There's not enough room, box up our current packet
                    info     = new ReliableInfo();
                    info.rid = stream.S2C_Reliable++;

                    //Don't add a lonely box
                    if (box.reliables.Count == 1)
                    {
                        info.packet = new Reliable(box.reliables[0].packet, info.rid, streamID);
                    }
                    else
                    {                           //Make sure the box is serialized
                        box.MakeSerialized(this, _handler);

                        info.packet = new Reliable(box, info.rid, streamID);
                    }

                    info.consolidateEvents(box.reliables);

                    reliables.Add(info);

                    box         = new ReliableBox(streamID);
                    currentSize = packetStartSize;
                }

                //Add the packet to the box list
                box.reliables.Add(pInfo);
                currentSize += pInfo.packet.Length + 1;
            }

            //If the last box has more than one packet, keep it
            if (box.reliables.Count > 1)
            {
                info     = new ReliableInfo();
                info.rid = stream.S2C_Reliable++;

                //Make sure the box is serialized
                box.MakeSerialized(this, _handler);

                info.packet = new Reliable(box, info.rid, streamID);
                info.consolidateEvents(box.reliables);

                reliables.Add(info);
            }
            else if (box.reliables.Count == 1)
            {                   //If it's only one packet, we don't need the box
                info        = new ReliableInfo();
                info.rid    = stream.S2C_Reliable++;
                info.packet = new Reliable(box.reliables[0].packet, info.rid, streamID);
                info.consolidateEvents(box.reliables[0]);

                reliables.Add(info);
            }

            //Boxed them all
            return(reliables);
        }
Esempio n. 37
0
        /// <summary>
        /// Gets the video arguments for transcoding.
        /// </summary>
        /// <param name="state">The <see cref="StreamState"/>.</param>
        /// <returns>The command line arguments for video transcoding.</returns>
        private string GetVideoArguments(StreamState state)
        {
            if (state.VideoStream == null)
            {
                return(string.Empty);
            }

            if (!state.IsOutputVideo)
            {
                return(string.Empty);
            }

            var codec = _encodingHelper.GetVideoEncoder(state, _encodingOptions);

            var args = "-codec:v:0 " + codec;

            // Prefer hvc1 to hev1.
            if (string.Equals(state.ActualOutputVideoCodec, "h265", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
            {
                args += " -tag:v:0 hvc1";
            }

            // if (state.EnableMpegtsM2TsMode)
            // {
            //     args += " -mpegts_m2ts_mode 1";
            // }

            // See if we can save come cpu cycles by avoiding encoding.
            if (EncodingHelper.IsCopyCodec(codec))
            {
                // If h264_mp4toannexb is ever added, do not use it for live tv.
                if (state.VideoStream != null && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
                {
                    string bitStreamArgs = EncodingHelper.GetBitStreamArgs(state.VideoStream);
                    if (!string.IsNullOrEmpty(bitStreamArgs))
                    {
                        args += " " + bitStreamArgs;
                    }
                }

                args += " -start_at_zero";
            }
            else
            {
                args += _encodingHelper.GetVideoQualityParam(state, codec, _encodingOptions, DefaultEncoderPreset);

                // Set the key frame params for video encoding to match the hls segment time.
                args += _encodingHelper.GetHlsVideoKeyFrameArguments(state, codec, state.SegmentLength, true, null);

                // Currenly b-frames in libx265 breaks the FMP4-HLS playback on iOS, disable it for now.
                if (string.Equals(codec, "libx265", StringComparison.OrdinalIgnoreCase))
                {
                    args += " -bf 0";
                }

                var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;

                if (hasGraphicalSubs)
                {
                    // Graphical subs overlay and resolution params.
                    args += _encodingHelper.GetGraphicalSubtitleParam(state, _encodingOptions, codec);
                }
                else
                {
                    // Resolution params.
                    args += _encodingHelper.GetOutputSizeParam(state, _encodingOptions, codec);
                }

                if (state.SubtitleStream == null || !state.SubtitleStream.IsExternal || state.SubtitleStream.IsTextSubtitleStream)
                {
                    args += " -start_at_zero";
                }
            }

            args += " -flags -global_header";

            if (!string.IsNullOrEmpty(state.OutputVideoSync))
            {
                args += " -vsync " + state.OutputVideoSync;
            }

            args += _encodingHelper.GetOutputFFlags(state);

            return(args);
        }
Esempio n. 38
0
        /// <summary>
        /// Adds the dlna headers.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
        /// <param name="startTimeTicks">The start time in ticks.</param>
        /// <param name="request">The <see cref="HttpRequest"/>.</param>
        /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param>
        public static void AddDlnaHeaders(
            StreamState state,
            IHeaderDictionary responseHeaders,
            bool isStaticallyStreamed,
            long?startTimeTicks,
            HttpRequest request,
            IDlnaManager dlnaManager)
        {
            if (!state.EnableDlnaHeaders)
            {
                return;
            }

            var profile = state.DeviceProfile;

            StringValues transferMode = request.Headers["transferMode.dlna.org"];

            responseHeaders.Add("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode.ToString());
            responseHeaders.Add("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*");

            if (state.RunTimeTicks.HasValue)
            {
                if (string.Equals(request.Headers["getMediaInfo.sec"], "1", StringComparison.OrdinalIgnoreCase))
                {
                    var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
                    responseHeaders.Add("MediaInfo.sec", string.Format(
                                            CultureInfo.InvariantCulture,
                                            "SEC_Duration={0};",
                                            Convert.ToInt32(ms)));
                }

                if (!isStaticallyStreamed && profile != null)
                {
                    AddTimeSeekResponseHeaders(state, responseHeaders, startTimeTicks);
                }
            }

            if (profile == null)
            {
                profile = dlnaManager.GetDefaultProfile();
            }

            var audioCodec = state.ActualOutputAudioCodec;

            if (!state.IsVideoRequest)
            {
                responseHeaders.Add("contentFeatures.dlna.org", new ContentFeatureBuilder(profile).BuildAudioHeader(
                                        state.OutputContainer,
                                        audioCodec,
                                        state.OutputAudioBitrate,
                                        state.OutputAudioSampleRate,
                                        state.OutputAudioChannels,
                                        state.OutputAudioBitDepth,
                                        isStaticallyStreamed,
                                        state.RunTimeTicks,
                                        state.TranscodeSeekInfo));
            }
            else
            {
                var videoCodec = state.ActualOutputVideoCodec;

                responseHeaders.Add(
                    "contentFeatures.dlna.org",
                    new ContentFeatureBuilder(profile).BuildVideoHeader(state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty);
            }
        }
Esempio n. 39
0
 /// <summary>
 /// Gets the segment file extension.
 /// </summary>
 /// <param name="state">The state.</param>
 /// <returns>System.String.</returns>
 protected override string GetSegmentFileExtension(StreamState state)
 {
     return(GetSegmentFileExtension(state.IsOutputVideo));
 }
Esempio n. 40
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ProgressiveStreamWriter" /> class.
 /// </summary>
 /// <param name="path">The path.</param>
 /// <param name="state">The state.</param>
 /// <param name="logger">The logger.</param>
 public ProgressiveStreamWriter(string path, StreamState state, ILogger logger)
 {
     Path   = path;
     State  = state;
     Logger = logger;
 }
Esempio n. 41
0
 private bool EnableCopyTs(StreamState state)
 {
     return(state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream);
 }
Esempio n. 42
0
 public void ResumeStream()
 {
     StreamState = StreamState.Resume;
 }
Esempio n. 43
0
 protected override int GetStartNumber(StreamState state)
 {
     return(GetStartNumber(state.VideoRequest));
 }
Esempio n. 44
0
 public void PauseStream()
 {
     StreamState = StreamState.Pause;
 }
Esempio n. 45
0
        /// <summary>
        /// Gets the static remote stream result.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
        /// <param name="cancellationTokenSource">The cancellation token source.</param>
        /// <returns>Task{System.Object}.</returns>
        private async Task <object> GetStaticRemoteStreamResult(StreamState state, Dictionary <string, string> responseHeaders, bool isHeadRequest, CancellationTokenSource cancellationTokenSource)
        {
            string useragent = null;

            state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);

            var trySupportSeek = false;

            var options = new HttpRequestOptions
            {
                Url               = state.MediaPath,
                UserAgent         = useragent,
                BufferContent     = false,
                CancellationToken = cancellationTokenSource.Token
            };

            if (trySupportSeek)
            {
                if (!string.IsNullOrWhiteSpace(Request.QueryString["Range"]))
                {
                    options.RequestHeaders["Range"] = Request.QueryString["Range"];
                }
            }
            var response = await HttpClient.GetResponse(options).ConfigureAwait(false);

            if (trySupportSeek)
            {
                foreach (var name in new[] { "Content-Range", "Accept-Ranges" })
                {
                    var val = response.Headers[name];
                    if (!string.IsNullOrWhiteSpace(val))
                    {
                        responseHeaders[name] = val;
                    }
                }
            }
            else
            {
                responseHeaders["Accept-Ranges"] = "none";
            }

            if (response.ContentLength.HasValue)
            {
                responseHeaders["Content-Length"] = response.ContentLength.Value.ToString(UsCulture);
            }

            if (isHeadRequest)
            {
                using (response)
                {
                    return(ResultFactory.GetResult(new byte[] { }, response.ContentType, responseHeaders));
                }
            }

            var result = new StaticRemoteStreamWriter(response);

            result.Headers["Content-Type"] = response.ContentType;

            // Add the response headers to the result object
            foreach (var header in responseHeaders)
            {
                result.Headers[header.Key] = header.Value;
            }

            return(result);
        }
Esempio n. 46
0
 /// <summary>
 /// Gets the segment file extension.
 /// </summary>
 /// <param name="state">The state.</param>
 /// <returns>System.String.</returns>
 protected override string GetSegmentFileExtension(StreamState state)
 {
     return(".ts");
 }
Esempio n. 47
0
 /// <summary>
 /// Gets the video arguments.
 /// </summary>
 protected abstract string GetVideoArguments(StreamState state, EncodingOptions encodingOptions);
Esempio n. 48
0
 protected virtual int GetStartNumber(StreamState state)
 {
     return(0);
 }
Esempio n. 49
0
        public async Task StartStreamAsync(Func <string, bool> processObject, Func <HttpWebRequest> generateWebRequest)
        {
            if (IsRunning)
            {
                throw new OperationCanceledException(Resources.Stream_IllegalMultipleStreams);
            }

            if (processObject == null)
            {
                throw new NullReferenceException(Resources.Stream_ObjectDelegateIsNull);
            }

            _lastException = null;
            _streamState   = StreamState.Resume;
            this.Raise(StreamStarted);

            _currentWebRequest = generateWebRequest();
            _currentReader     = await InitWebRequest(_currentWebRequest);

            if (_lastException != null)
            {
                _streamState = StreamState.Stop;
            }

            int errorOccured = 0;

            while (StreamState != StreamState.Stop)
            {
                if (StreamState == StreamState.Pause)
                {
                    using (EventWaitHandle tmpEvent = new ManualResetEvent(false))
                    {
                        tmpEvent.WaitOne(TimeSpan.FromSeconds(STREAM_RESUME_DELAY));
                    }
                    continue;
                }

                try
                {
                    string jsonResponse = await _currentReader.ReadLineAsync();

                    #region Error Checking

                    if (jsonResponse == null)
                    {
                        if (errorOccured == 0)
                        {
                            ++errorOccured;
                            continue;
                        }

                        if (errorOccured == 1)
                        {
                            ++errorOccured;
                            _currentWebRequest.Abort();
                            _currentReader = await InitWebRequest(_currentWebRequest);

                            continue;
                        }

                        if (errorOccured == 2)
                        {
                            ++errorOccured;
                            _currentWebRequest.Abort();
                            _currentWebRequest = generateWebRequest();
                            _currentReader     = await InitWebRequest(_currentWebRequest);

                            continue;
                        }

                        break;
                    }

                    errorOccured = 0;

                    #endregion

                    if (jsonResponse == String.Empty)
                    {
                        continue;
                    }

                    if (StreamState == StreamState.Resume && !processObject(jsonResponse))
                    {
                        StreamState = StreamState.Stop;
                        break;
                    }
                }
                catch (WebException wex)
                {
                    if (_exceptionHandler.LogExceptions)
                    {
                        _exceptionHandler.AddWebException(wex, String.Empty);
                    }

                    if (!_exceptionHandler.SwallowWebExceptions)
                    {
                        throw;
                    }
                }
                catch (Exception ex)
                {
                    _lastException = ex;
                    if (ex is IOException && StreamState == StreamState.Stop)
                    {
                        _lastException = null;
                    }

                    break;
                }
            }

            if (_currentWebRequest != null)
            {
                _currentWebRequest.Abort();
            }

            if (_currentReader != null)
            {
                _currentReader.Dispose();
            }

            StreamState = StreamState.Stop;
        }
Esempio n. 50
0
        /// <summary>
        /// Gets the command line arguments for ffmpeg.
        /// </summary>
        /// <param name="outputPath">The output path of the file.</param>
        /// <param name="state">The <see cref="StreamState"/>.</param>
        /// <returns>The command line arguments as a string.</returns>
        private string GetCommandLineArguments(string outputPath, StreamState state)
        {
            var videoCodec    = _encodingHelper.GetVideoEncoder(state, _encodingOptions);
            var threads       = EncodingHelper.GetNumberOfThreads(state, _encodingOptions, videoCodec); // GetNumberOfThreads is static.
            var inputModifier = _encodingHelper.GetInputModifier(state, _encodingOptions);
            var mapArgs       = state.IsOutputVideo ? _encodingHelper.GetMapArgs(state) : string.Empty;

            var directory = Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath));
            var outputFileNameWithoutExtension = Path.GetFileNameWithoutExtension(outputPath);
            var outputPrefix    = Path.Combine(directory, outputFileNameWithoutExtension);
            var outputExtension = EncodingHelper.GetSegmentFileExtension(state.Request.SegmentContainer);
            var outputTsArg     = outputPrefix + "%d" + outputExtension;

            var segmentFormat = outputExtension.TrimStart('.');

            if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
            {
                segmentFormat = "mpegts";
            }
            else if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase))
            {
                var outputFmp4HeaderArg = string.Empty;
                var isWindows           = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                if (isWindows)
                {
                    // on Windows, the path of fmp4 header file needs to be configured
                    outputFmp4HeaderArg = " -hls_fmp4_init_filename \"" + outputPrefix + "-1" + outputExtension + "\"";
                }
                else
                {
                    // on Linux/Unix, ffmpeg generate fmp4 header file to m3u8 output folder
                    outputFmp4HeaderArg = " -hls_fmp4_init_filename \"" + outputFileNameWithoutExtension + "-1" + outputExtension + "\"";
                }

                segmentFormat = "fmp4" + outputFmp4HeaderArg;
            }
            else
            {
                _logger.LogError("Invalid HLS segment container: {SegmentFormat}", segmentFormat);
            }

            var maxMuxingQueueSize = _encodingOptions.MaxMuxingQueueSize > 128
                ? _encodingOptions.MaxMuxingQueueSize.ToString(CultureInfo.InvariantCulture)
                : "128";

            var baseUrlParam = string.Format(
                CultureInfo.InvariantCulture,
                "\"hls/{0}/\"",
                Path.GetFileNameWithoutExtension(outputPath));

            return(string.Format(
                       CultureInfo.InvariantCulture,
                       "{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -copyts -avoid_negative_ts disabled -max_muxing_queue_size {6} -f hls -max_delay 5000000 -hls_time {7} -hls_segment_type {8} -start_number 0 -hls_base_url {9} -hls_playlist_type event -hls_segment_filename \"{10}\" -y \"{11}\"",
                       inputModifier,
                       _encodingHelper.GetInputArgument(state, _encodingOptions),
                       threads,
                       mapArgs,
                       GetVideoArguments(state),
                       GetAudioArguments(state),
                       maxMuxingQueueSize,
                       state.SegmentLength.ToString(CultureInfo.InvariantCulture),
                       segmentFormat,
                       baseUrlParam,
                       outputTsArg,
                       outputPath).Trim());
        }
Esempio n. 51
0
        /// <summary>
        /// Gets the stream result.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
        /// <param name="cancellationTokenSource">The cancellation token source.</param>
        /// <returns>Task{System.Object}.</returns>
        private async Task <object> GetStreamResult(StreamState state, IDictionary <string, string> responseHeaders, bool isHeadRequest, CancellationTokenSource cancellationTokenSource)
        {
            // Use the command line args with a dummy playlist path
            var outputPath = state.OutputFilePath;

            responseHeaders["Accept-Ranges"] = "none";

            var contentType = state.GetMimeType(outputPath);

            var contentLength = state.EstimateContentLength ? GetEstimatedContentLength(state) : null;

            if (contentLength.HasValue)
            {
                responseHeaders["Content-Length"] = contentLength.Value.ToString(UsCulture);
            }

            // Headers only
            if (isHeadRequest)
            {
                var streamResult = ResultFactory.GetResult(new byte[] { }, contentType, responseHeaders);

                if (!contentLength.HasValue)
                {
                    var hasOptions = streamResult as IHasOptions;
                    if (hasOptions != null)
                    {
                        if (hasOptions.Options.ContainsKey("Content-Length"))
                        {
                            hasOptions.Options.Remove("Content-Length");
                        }
                    }
                }

                return(streamResult);
            }

            await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);

            try
            {
                TranscodingJob job;

                if (!File.Exists(outputPath))
                {
                    job = await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false);
                }
                else
                {
                    job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
                    state.Dispose();
                }

                var result = new ProgressiveStreamWriter(outputPath, Logger, FileSystem, job);

                result.Options["Content-Type"] = contentType;

                // Add the response headers to the result object
                foreach (var item in responseHeaders)
                {
                    result.Options[item.Key] = item.Value;
                }

                return(result);
            }
            finally
            {
                ApiEntryPoint.Instance.TranscodingStartLock.Release();
            }
        }
Esempio n. 52
0
        private static void ApplyDeviceProfileSettings(StreamState state, IDlnaManager dlnaManager, IDeviceManager deviceManager, HttpRequest request, string?deviceProfileId, bool? @static)
        {
            var headers = request.Headers;

            if (!string.IsNullOrWhiteSpace(deviceProfileId))
            {
                state.DeviceProfile = dlnaManager.GetProfile(deviceProfileId);
            }
            else if (!string.IsNullOrWhiteSpace(deviceProfileId))
            {
                var caps = deviceManager.GetCapabilities(deviceProfileId);

                state.DeviceProfile = caps == null?dlnaManager.GetProfile(headers) : caps.DeviceProfile;
            }

            var profile = state.DeviceProfile;

            if (profile == null)
            {
                // Don't use settings from the default profile.
                // Only use a specific profile if it was requested.
                return;
            }

            var audioCodec = state.ActualOutputAudioCodec;
            var videoCodec = state.ActualOutputVideoCodec;

            var mediaProfile = !state.IsVideoRequest
                ? profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth)
                : profile.GetVideoMediaProfile(
                state.OutputContainer,
                audioCodec,
                videoCodec,
                state.OutputWidth,
                state.OutputHeight,
                state.TargetVideoBitDepth,
                state.OutputVideoBitrate,
                state.TargetVideoProfile,
                state.TargetVideoLevel,
                state.TargetFramerate,
                state.TargetPacketLength,
                state.TargetTimestamp,
                state.IsTargetAnamorphic,
                state.IsTargetInterlaced,
                state.TargetRefFrames,
                state.TargetVideoStreamCount,
                state.TargetAudioStreamCount,
                state.TargetVideoCodecTag,
                state.IsTargetAVC);

            if (mediaProfile != null)
            {
                state.MimeType = mediaProfile.MimeType;
            }

            if (!(@static.HasValue && @static.Value))
            {
                var transcodingProfile = !state.IsVideoRequest ? profile.GetAudioTranscodingProfile(state.OutputContainer, audioCodec) : profile.GetVideoTranscodingProfile(state.OutputContainer, audioCodec, videoCodec);

                if (transcodingProfile != null)
                {
                    state.EstimateContentLength = transcodingProfile.EstimateContentLength;
                    // state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
                    state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;

                    if (state.VideoRequest != null)
                    {
                        state.VideoRequest.CopyTimestamps            = transcodingProfile.CopyTimestamps;
                        state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
                    }
                }
            }
        }
Esempio n. 53
0
 internal MockStream(StreamState streamState, bool isInitiator)
 {
     _streamState = streamState;
     _isInitiator = isInitiator;
 }
Esempio n. 54
0
        protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
        {
            var itsOffsetMs = 0;

            var itsOffset = itsOffsetMs == 0 ? string.Empty : string.Format("-itsoffset {0} ", TimeSpan.FromMilliseconds(itsOffsetMs).TotalSeconds.ToString(CultureInfo.InvariantCulture));

            var videoCodec = EncodingHelper.GetVideoEncoder(state, encodingOptions);

            var threads = EncodingHelper.GetNumberOfThreads(state, encodingOptions, videoCodec);

            var inputModifier = EncodingHelper.GetInputModifier(state, encodingOptions);

            // If isEncoding is true we're actually starting ffmpeg
            var startNumberParam = isEncoding ? GetStartNumber(state).ToString(CultureInfo.InvariantCulture) : "0";

            var baseUrlParam = string.Empty;

            if (state.Request is GetLiveHlsStream)
            {
                baseUrlParam = string.Format(" -hls_base_url \"{0}/\"",
                                             "hls/" + Path.GetFileNameWithoutExtension(outputPath));
            }

            var useGenericSegmenter = true;

            if (useGenericSegmenter)
            {
                var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);

                var timeDeltaParam = string.Empty;

                var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
                if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
                {
                    segmentFormat = "mpegts";
                }

                baseUrlParam = string.Format("\"{0}/\"", "hls/" + Path.GetFileNameWithoutExtension(outputPath));

                return(string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format {11} -segment_list_entry_prefix {12} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
                                     inputModifier,
                                     EncodingHelper.GetInputArgument(state, encodingOptions),
                                     threads,
                                     EncodingHelper.GetMapArgs(state),
                                     GetVideoArguments(state, encodingOptions),
                                     GetAudioArguments(state, encodingOptions),
                                     state.SegmentLength.ToString(CultureInfo.InvariantCulture),
                                     startNumberParam,
                                     outputPath,
                                     outputTsArg,
                                     timeDeltaParam,
                                     segmentFormat,
                                     baseUrlParam
                                     ).Trim());
            }

            // add when stream copying?
            // -avoid_negative_ts make_zero -fflags +genpts

            var args = string.Format("{0} {1} {2} -map_metadata -1 -map_chapters -1 -threads {3} {4} {5} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero {6} -hls_time {7} -individual_header_trailer 0 -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
                                     itsOffset,
                                     inputModifier,
                                     EncodingHelper.GetInputArgument(state, encodingOptions),
                                     threads,
                                     EncodingHelper.GetMapArgs(state),
                                     GetVideoArguments(state, encodingOptions),
                                     GetAudioArguments(state, encodingOptions),
                                     state.SegmentLength.ToString(CultureInfo.InvariantCulture),
                                     startNumberParam,
                                     state.HlsListSize.ToString(CultureInfo.InvariantCulture),
                                     baseUrlParam,
                                     outputPath
                                     ).Trim();

            return(args);
        }
Esempio n. 55
0
        protected override string GetVideoArguments(StreamState state)
        {
            if (!state.IsOutputVideo)
            {
                return string.Empty;
            }

            var codec = GetVideoEncoder(state);

            var args = "-codec:v:0 " + codec;

            if (state.EnableMpegtsM2TsMode)
            {
                args += " -mpegts_m2ts_mode 1";
            }

            // See if we can save come cpu cycles by avoiding encoding
            if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
            {
                if (state.VideoStream != null && IsH264(state.VideoStream))
                {
                    args += " -bsf:v h264_mp4toannexb";
                }

                args += " -flags -global_header -sc_threshold 0";
            }
            else
            {
                var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
                    state.SegmentLength.ToString(UsCulture));

                var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;

                args += " " + GetVideoQualityParam(state, GetH264Encoder(state), true) + keyFrameArg;

                //args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";

                // Add resolution params, if specified
                if (!hasGraphicalSubs)
                {
                    args += GetOutputSizeParam(state, codec, EnableCopyTs(state));
                }

                // This is for internal graphical subs
                if (hasGraphicalSubs)
                {
                    args += GetGraphicalSubtitleParam(state, codec);
                }

                args += " -flags -global_header -sc_threshold 0";
            }

            return args;
        }
Esempio n. 56
0
        /// <summary>
        /// Adds the dlna headers.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="responseHeaders">The response headers.</param>
        /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
        private void AddDlnaHeaders(StreamState state, IDictionary <string, string> responseHeaders, bool isStaticallyStreamed)
        {
            var timeSeek = RequestContext.GetHeader("TimeSeekRange.dlna.org");

            if (!string.IsNullOrEmpty(timeSeek))
            {
                ResultFactory.ThrowError(406, "Time seek not supported during encoding.", responseHeaders);
                return;
            }

            var transferMode = RequestContext.GetHeader("transferMode.dlna.org");

            responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;

            var contentFeatures = string.Empty;
            var extension       = GetOutputFileExtension(state);

            // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
            var orgOp = isStaticallyStreamed ? ";DLNA.ORG_OP=01" : ";DLNA.ORG_OP=00";

            // 0 = native, 1 = transcoded
            var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";

            const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";

            if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase))
            {
                contentFeatures = "DLNA.ORG_PN=MP3";
            }
            else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase))
            {
                contentFeatures = "DLNA.ORG_PN=AAC_ISO";
            }
            else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase))
            {
                contentFeatures = "DLNA.ORG_PN=WMABASE";
            }
            else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase))
            {
                contentFeatures = "DLNA.ORG_PN=AVI";
            }
            else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase))
            {
                contentFeatures = "DLNA.ORG_PN=MPEG4_P2_SP_AAC";
            }
            else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase))
            {
                contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
            }
            else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase))
            {
                contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
            }
            else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase))
            {
                // ??
                contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE";
            }
            else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase))
            {
                // ??
                contentFeatures = "";
            }

            if (!string.IsNullOrEmpty(contentFeatures))
            {
                responseHeaders["ContentFeatures.DLNA.ORG"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
            }
        }
Esempio n. 57
0
        protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
        {
            var threads = GetNumberOfThreads(state, false);

            var inputModifier = GetInputModifier(state, false);

            // If isEncoding is true we're actually starting ffmpeg
            var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0";

            var toTimeParam = string.Empty;
            var timestampOffsetParam = string.Empty;

            if (state.IsOutputVideo && !EnableCopyTs(state) && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && (state.Request.StartTimeTicks ?? 0) > 0)
            {
                timestampOffsetParam = " -output_ts_offset " + MediaEncoder.GetTimeParameter(state.Request.StartTimeTicks ?? 0).ToString(CultureInfo.InvariantCulture);
            }

            var mapArgs = state.IsOutputVideo ? GetMapArgs(state) : string.Empty;

            //var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state);

            //return string.Format("{0} {11} {1}{10} -map_metadata -1 -threads {2} {3} {4} {5} -f segment -segment_time {6} -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
            //    inputModifier,
            //    GetInputArgument(state),
            //    threads,
            //    mapArgs,
            //    GetVideoArguments(state),
            //    GetAudioArguments(state),
            //    state.SegmentLength.ToString(UsCulture),
            //    startNumberParam,
            //    outputPath,
            //    outputTsArg,
            //            slowSeekParam,
            //            toTimeParam
            //    ).Trim();

            return string.Format("{0}{11} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -hls_time {7} -start_number {8} -hls_list_size {9} -y \"{10}\"",
                            inputModifier,
                            GetInputArgument(state),
                            threads,
                            mapArgs,
                            GetVideoArguments(state),
                            timestampOffsetParam,
                            GetAudioArguments(state),
                            state.SegmentLength.ToString(UsCulture),
                            startNumberParam,
                            state.HlsListSize.ToString(UsCulture),
                            outputPath,
                            toTimeParam
                            ).Trim();
        }
Esempio n. 58
0
        /// <summary>
        /// Gets the output file extension.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>System.String.</returns>
        protected override string GetOutputFileExtension(StreamState state)
        {
            var ext = base.GetOutputFileExtension(state);

            if (!string.IsNullOrEmpty(ext))
            {
                return(ext);
            }

            var videoRequest = state.Request as VideoStreamRequest;

            // Try to infer based on the desired video codec
            if (videoRequest != null && videoRequest.VideoCodec.HasValue)
            {
                var video = state.Item as Video;

                if (video != null)
                {
                    switch (videoRequest.VideoCodec.Value)
                    {
                    case VideoCodecs.H264:
                        return(".ts");

                    case VideoCodecs.Theora:
                        return(".ogv");

                    case VideoCodecs.Vpx:
                        return(".webm");

                    case VideoCodecs.Wmv:
                        return(".asf");
                    }
                }
            }

            // Try to infer based on the desired audio codec
            if (state.Request.AudioCodec.HasValue)
            {
                var audio = state.Item as Audio;

                if (audio != null)
                {
                    switch (state.Request.AudioCodec.Value)
                    {
                    case AudioCodecs.Aac:
                        return(".aac");

                    case AudioCodecs.Mp3:
                        return(".mp3");

                    case AudioCodecs.Vorbis:
                        return(".ogg");

                    case AudioCodecs.Wma:
                        return(".wma");
                    }
                }
            }

            return(null);
        }
Esempio n. 59
0
 /// <summary>
 /// Gets the segment file extension.
 /// </summary>
 /// <param name="state">The state.</param>
 /// <returns>System.String.</returns>
 protected override string GetSegmentFileExtension(StreamState state)
 {
     return GetSegmentFileExtension(state.IsOutputVideo);
 }
Esempio n. 60
0
 protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
 {
     return(EncodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, outputPath, GetDefaultH264Preset()));
 }