Ejemplo n.º 1
0
        /// <summary>
        /// Calculates the next chunk to get for the given stream
        /// </summary>
        /// <param name="stream">the stream to look at</param>
        /// <returns>the next bitrate for this stream</returns>
        private ulong GetNextBitrateForStream(StreamInfo stream)
        {
            int streamIndex = stream.StreamId;
            if (m_heuristicsMode[streamIndex] == HeuristicsMode.Full)
            {
                // Use the full mode calculation
                // Get our network stats for this stream
                NetworkMediaInfo networkMediaInfo = m_networkMediaInfo[streamIndex];

                // Find the closest bitrate
                ulong nextBitRate = networkMediaInfo.FindClosestBitrateByValue(networkMediaInfo.NextBitrate);
                NhTrace("INFO", streamIndex, "Next bit rate:{0}", nextBitRate);

                // Return Kilobits per second
                return nextBitRate;
            }
            else
            {
                // There is no other values for now, so that's: if (useHeuristicsMode[streamIndex] == HeuristicsMode.FixedRate)
                // Grab a bitrate from the bitrate array (currently always selects the first bitrate).
                return stream.Bitrates[m_fixedBitrateIndex[streamIndex]];
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Adds a stream to this manifest
        /// </summary>
        /// <param name="streamIndexInfo">the stream to add</param>
        public void AddStream(StreamInfo streamIndexInfo)
        {
            // Let's go through and fixup some of the info in the
            // stream and make sure that it is all valid
            streamIndexInfo.CalculateStartTimes();

            // Now add it to our list of streams
            m_streams.Add(streamIndexInfo);

            // We can only have 1 audio and 1 video stream active, so let's keep track
            // of which ones are active if we have more than one
            if (m_activeStreams[(int)streamIndexInfo.MediaType] == null)
            {
                m_activeStreams[(int)streamIndexInfo.MediaType] = streamIndexInfo;
            }

            // Add our media stream descriptor
            m_streamDescriptions.Add(streamIndexInfo.Description);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Parse the stream section of the manifest
        /// </summary>
        /// <param name="manifest">The XML dom of the stream section in the manifest</param>
        /// <param name="streamId">The Id of the stream we are parsing</param>
        /// <param name="manifestBaseUrl">the url of the manifest we are parsing</param>
        /// <param name="manifestInfo">the manifest we are parsing</param>
        /// <returns>A StreamInfo describing the stream at streamId, or null if one was not found</returns>
        private static StreamInfo ParseStreamInfo(XmlReader manifest, int streamId, string manifestBaseUrl, ManifestInfo manifestInfo)
        {
            string mediaTypeStr = manifest.GetAttribute(StreamIndexTypeAttribute);
            bool bHaveFirstBitrate = false;

            // Pick out text types since we handle those separately
            if (mediaTypeStr.ToUpper(CultureInfo.InvariantCulture).Equals("TEXT"))
            {
                // Parse the text stream and return null
                ParseTextStream(manifest, manifestInfo);
                return null;
            }

            string baseUrl = manifest.GetAttribute(StreamIndexUrlAttribute);
            int numberOfChunks = Convert.ToInt32(manifest.GetAttribute(StreamIndexChunksAttribute), CultureInfo.InvariantCulture);
            if (mediaTypeStr == null || baseUrl == null || numberOfChunks < 1)
            {
                throw new AdaptiveStreamingException("Stream description in the manifest " + streamId.ToString(CultureInfo.InvariantCulture) + " is missing mandatory attributes (media type, subtype, base URL or number of chunks)");
            }

            MediaStreamType mediaType = mediaTypeStr.ToUpper(CultureInfo.InvariantCulture).Equals("VIDEO") ? MediaStreamType.Video : mediaTypeStr.ToUpper(CultureInfo.InvariantCulture).Equals("AUDIO") ? MediaStreamType.Audio : MediaStreamType.Script;
            if (mediaType == MediaStreamType.Script)
            {
                throw new AdaptiveStreamingException("Stream media type in manifest may be 'audio' or 'video' only");
            }

            if (!baseUrl.ToUpper(CultureInfo.InvariantCulture).StartsWith("HTTP://", StringComparison.OrdinalIgnoreCase))
            {
                baseUrl = manifestBaseUrl + baseUrl;
            }

            // Get the language attribute
            string language = manifest.GetAttribute(StreamIndexLanguageAttribute);

            if (language == null)
            {
                language = string.Empty;
            }

            StreamInfo info = new StreamInfo(baseUrl, language, numberOfChunks, mediaType, streamId);
            ulong maxBitrate = 0;
            int displayAspectRatioWidth = 0;
            int displayAspectRatioHeight = 0;
            int maxBitrateWidth = 0;
            int maxBitrateHeight = 0;
            bool bIsVideoStream = true;

            while (manifest.Read())
            {
                // Get the available bitrates
                if (manifest.IsStartElement(QualityLevelElement))
                {
                    // Missing or malformed attribute kbps will result in failure, which is what we want
                    ulong bitrate = Convert.ToUInt64(manifest.GetAttribute(QualityLevelBitrateAttribute), CultureInfo.InvariantCulture);
                    Dictionary<MediaStreamAttributeKeys, string> attributes = new Dictionary<MediaStreamAttributeKeys, string>(4);

                    // Get the FourCC for this quality level
                    string fourCC = manifest.GetAttribute(QualityLevelFourCCAttribute);

                    if (fourCC != null)
                    {
                        attributes.Add(MediaStreamAttributeKeys.VideoFourCC, fourCC);
                    }

                    // Get the width of this stream
                    string width = manifest.GetAttribute(QualityLevelWidthAttribute);

                    if (width != null)
                    {
                        attributes.Add(MediaStreamAttributeKeys.Width, width);
                    }

                    // Get the height of this stream
                    string height = manifest.GetAttribute(QualityLevelHeightAttribute);

                    if (height != null)
                    {
                        attributes.Add(MediaStreamAttributeKeys.Height, height);
                    }

                    // Get the video codec data
                    string codecPrivateData = manifest.GetAttribute(QualityLevelCodecPrivateDataAttribute);

                    if (codecPrivateData != null)
                    {
                        attributes.Add(MediaStreamAttributeKeys.CodecPrivateData, codecPrivateData);
                    }

                    // Get the wave format ex. Note we will only have one (codec private data) or the other
                    // (wave format ex)
                    string waveFormatEx = manifest.GetAttribute(QualityLevelWaveFormatExAttribute);

                    if (waveFormatEx != null)
                    {
                        if (codecPrivateData != null)
                        {
                            throw new AdaptiveStreamingException("Cannot have both a CodecPrivateData and a WaveFormatEx attribute in the same QualityLevel element.");
                        }
                        bIsVideoStream = false;
                        attributes.Add(MediaStreamAttributeKeys.CodecPrivateData, waveFormatEx);
                    }

                    if (!bHaveFirstBitrate)
                    {
                        bHaveFirstBitrate = true;

                        if (bIsVideoStream)
                        {
                            displayAspectRatioHeight = int.Parse(height, CultureInfo.InvariantCulture);
                            displayAspectRatioWidth = int.Parse(width, CultureInfo.InvariantCulture);
                        }
                    }

                    // Add this bitrate and these attributes to the stream info
                    info.AddBitrate(bitrate, attributes);

                    if (bitrate > maxBitrate)
                    {
                        maxBitrate = bitrate;

                        if (bIsVideoStream)
                        {
                            maxBitrateHeight = int.Parse(height, CultureInfo.InvariantCulture);
                            maxBitrateWidth = int.Parse(width, CultureInfo.InvariantCulture);
                        }
                    }
                }
                else if (manifest.IsStartElement("c"))
                {
                    // Getting chunk information
                    int id = 0;
                    try
                    {
                        // Missing or malformed attributes n or d will result in failure, which is what we want
                        id = Convert.ToInt32(manifest.GetAttribute("n"), CultureInfo.InvariantCulture);

                        // Ignore out-of-range chunk id's to simplify experimental manifest tinkering (truncation for test purposes).
                        if (id < info.NumberOfChunksInStream)
                        {
                            // Add a new media chunk to our stream info
                            ulong chunkDuration = Convert.ToUInt64(manifest.GetAttribute("d"), CultureInfo.InvariantCulture);
                            info.AddMediaChunk(id, chunkDuration);
                        }
                    }
                    catch (ArgumentOutOfRangeException e)
                    {
                        throw new AdaptiveStreamingException(String.Format(CultureInfo.InvariantCulture, "Bad manifest format: chunk ID {0} is out of range.", id), e);
                    }
                }
                else if (manifest.Name.Equals("StreamIndex"))
                {
                    break;
                }

                // We explicitly ignore content that we don't understand, as well as whitespace, comments etc.
            }

            // Let's fix up the aspect ratio of the highest bitrate stream. We need to find the
            // combination that gives us the largest buffer size.
            IDictionary<MediaStreamAttributeKeys, string> mediaAttributes = info.GetAttributesForBitrate(maxBitrate);
            if(bIsVideoStream)
            {
                // First try the width
                int testWidth = displayAspectRatioWidth * maxBitrateHeight;
                testWidth = (int)((double)(testWidth) / (double)displayAspectRatioHeight);

                // Now round it up to the nearest four
                testWidth += 3;
                testWidth -= testWidth % 4;

                // Now try the height
                int testHeight = displayAspectRatioHeight * maxBitrateWidth;
                testHeight = (int)((double)(testHeight) / (double)displayAspectRatioWidth);

                // Now round it up to the nearest four
                testHeight+= 3;
                testHeight -= testHeight % 4;

                // Calculate the buffer sizes
                int bufferSizeOriginal = maxBitrateWidth * maxBitrateHeight;
                int bufferSizeWidth = testWidth * maxBitrateHeight;
                int bufferSizeHeight = testHeight * maxBitrateWidth;

                if (bufferSizeWidth >= bufferSizeHeight && bufferSizeWidth >= bufferSizeOriginal)
                {
                    maxBitrateWidth = testWidth;
                }
                else if (bufferSizeHeight >= bufferSizeWidth && bufferSizeHeight >= bufferSizeOriginal)
                {
                    maxBitrateHeight = testHeight;
                }

                mediaAttributes.Remove(MediaStreamAttributeKeys.Width);
                mediaAttributes.Remove(MediaStreamAttributeKeys.Height);
                mediaAttributes.Add(MediaStreamAttributeKeys.Width, maxBitrateWidth.ToString(CultureInfo.InvariantCulture));
                mediaAttributes.Add(MediaStreamAttributeKeys.Height, maxBitrateHeight.ToString(CultureInfo.InvariantCulture));
            }

            // Set the description to be the highest bitrate item.
            info.Description = new MediaStreamDescription(info.MediaType, mediaAttributes);
            info.Valid = true;

            return info;
        }