示例#1
0
        protected FilePosition GetFilePosition(double searchOffset, AsfStreamType streamType, bool isStart)
        {
            FilePosition         requestedPosition = new FilePosition(FileName, StartTimeOffsetVideo, 0, MediaType, (int)(searchOffset * 1000));
            bool                 found             = false;
            bool                 isKeyframe        = false;
            bool                 wasKeyFrame       = false;
            long                 maxOffset         = 0;
            long                 minOffset         = 0;
            UInt32               startTimeOffset   = requestedPosition.TimeOffset;
            int                  diff       = requestedPosition.Delta;
            int                  prevDiff   = 0;
            FileStream           fs         = null;
            long                 fileOffset = 0;
            uint                 targetTimeOffset;
            string               fileName       = requestedPosition.FileName;
            AsfFileConfiguration asfConfig      = _asfConfig;
            uint                 TargetStreamId = streamType == AsfStreamType.asfAudio ? _asfConfig.AsfAudioStreamId : _asfConfig.AsfVideoStreamId;

            UInt32 finalTimeOffset = (UInt32)Math.Max(0, startTimeOffset + diff);

            targetTimeOffset = finalTimeOffset;

            UInt32 maxTimeDifference     = streamType == AsfStreamType.asfAudio ? AsfConstants.ASF_TIME_THRESHOLD_START_AUDIO : AsfConstants.ASF_TIME_THRESHOLD;
            uint   averagePacketDuration = GetAveragePacketDuration();

            minOffset = asfConfig.AsfHeaderSize;

            //set maxOffset to start of last packet
            maxOffset = asfConfig.AsfHeaderSize + (asfConfig.AsfPacketCount - 1) * asfConfig.AsfPacketSize;
            long packetCount = asfConfig.AsfPacketCount;

            // open the file
            try
            {
                fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            }
            catch (Exception) { return(null); }

            int  prevPacketJumpCount = 0;
            bool wasBroadSearch      = false;
            int  totalJumpCount      = 0;
            int  packetJumpCount     = 0;
            long searchMaxOffset     = maxOffset;
            long searchMinOffset     = minOffset;

            fileOffset = minOffset;

            while (!found)
            {
                totalJumpCount++;
                if (totalJumpCount > 500) //totally arbitrary number after which to give up
                {
                    return(null);
                }


                packetJumpCount = (int)Math.Round((float)diff / averagePacketDuration);
                if (Math.Abs(packetJumpCount) >= Math.Abs(prevPacketJumpCount) && Math.Abs(prevPacketJumpCount) > 0)
                { //we have to make sure that we converge, for this reason the number of packets we jump has to decrease at every iteration
                    if (Math.Abs(prevPacketJumpCount) > 1)
                    {
                        packetJumpCount = packetJumpCount > 0 ? Math.Abs(prevPacketJumpCount) - 1 : -Math.Abs(prevPacketJumpCount) + 1;
                    }
                    else
                    {
                        packetJumpCount = packetJumpCount > 0 ? 1 : -1;
                    }
                }
                prevPacketJumpCount = packetJumpCount;

                long byteJump = asfConfig.AsfPacketSize * packetJumpCount;

                if (fileOffset + byteJump > maxOffset)
                {
                    byteJump            = maxOffset - fileOffset;
                    packetJumpCount     = (int)(byteJump / asfConfig.AsfPacketSize);
                    prevPacketJumpCount = packetJumpCount;
                }
                else if (fileOffset + byteJump < minOffset)
                {
                    byteJump            = minOffset - fileOffset;
                    packetJumpCount     = (int)(byteJump / asfConfig.AsfPacketSize);
                    prevPacketJumpCount = packetJumpCount;
                }

                if (fs.Seek(fileOffset + byteJump, SeekOrigin.Begin) != fileOffset + byteJump)
                {
                    return(null);
                }
                fileOffset += byteJump;

                //track backwards if we cannot find target stream in this packet
                while (!FindNextTimeOffset(asfConfig, fs, out isKeyframe, ref startTimeOffset, TargetStreamId))
                {
                    fileOffset -= asfConfig.AsfPacketSize;
                    if (fs.Seek(fileOffset, SeekOrigin.Begin) != fileOffset)
                    {
                        return(null);
                    }
                }
                diff = (int)((long)finalTimeOffset - (long)startTimeOffset);
                if (Math.Abs(diff) <= maxTimeDifference)
                {
                    found = true;
                    if (isStart)
                    {
                        string.Format("Found video match at offset: {0} bytes, delta = {1} ms", fileOffset, diff).Log(LogLevel.logDetail);
                    }
                }
                else
                {       //handle case of multiple frames in packet, return the packet right after target time since we will track back to previous keyframe anyway
                    if (diff > 0 && prevDiff < 0 && Math.Abs(packetJumpCount) == 1 && !wasBroadSearch)
                    {
                        found = true;
                        if (isStart)
                        {
                            string.Format("Found video match at offset: {0} bytes, delta = {1} ms", fileOffset, diff).Log(LogLevel.logDetail);
                        }
                    }
                    wasBroadSearch = false;
                }
                prevDiff = diff;
            }

            if (found && !isStart)
            {
                bool foundAudio = false;
                bool temp;
                //keep moving forward until we are PAST the requested end time or reach the end of the current asset
                while ((!foundAudio || (foundAudio && diff > 0)) && fileOffset <= maxOffset)
                {
                    if (fileOffset <= maxOffset)
                    {
                        if (fs.Seek(fileOffset + asfConfig.AsfPacketSize, SeekOrigin.Begin) != fileOffset + asfConfig.AsfPacketSize)
                        {
                            break;
                        }
                        foundAudio  = FindNextTimeOffset(asfConfig, fs, out temp, ref startTimeOffset, asfConfig.AsfAudioStreamId, false);
                        fileOffset += asfConfig.AsfPacketSize;
                    }

                    //calculate again
                    if (foundAudio)
                    {
                        diff             = (int)((long)finalTimeOffset - (long)startTimeOffset);
                        targetTimeOffset = startTimeOffset;
                    }
                }
            }
            else if (found && isStart)
            {
                //now we have to find the previous keyframe, which also might be in the previous file if any exists
                //even if current frame is a keyframe we have to go back if the keyframe is after the match time so the correct still frame is shown in all cases
                //save the presentation Time of the match though, this time all earlier packets will be set to before preroll, so the
                //stream "fast forwards" until the match time
                targetTimeOffset = finalTimeOffset;

                if (streamType == AsfStreamType.asfAudio)
                {
                    wasKeyFrame = true; // Every packet in audio is a keyframe.
                    isKeyframe  = true;
                }
                else //Video
                {
                    wasKeyFrame = isKeyframe;
                    isKeyframe  = false; //always go back to the previous key frame if possible to avoid edge condition with multiple frames in the same packet
                }

                while (((streamType != AsfStreamType.asfAudio && !isKeyframe) || diff < 0) && fileOffset > minOffset)
                {
                    fileOffset -= asfConfig.AsfPacketSize;
                    if (fileOffset >= asfConfig.AsfHeaderSize)
                    {
                        fs.Seek(fileOffset, SeekOrigin.Begin);
                        FindNextTimeOffset(asfConfig, fs, out isKeyframe, ref startTimeOffset, TargetStreamId);
                        diff = (int)((long)finalTimeOffset - (long)startTimeOffset);
                    }
                    else
                    {
                        fileOffset = minOffset;
                        fs.Dispose();
                        //cannot find any earlier keyframe, just return position/file as is
                        if (found && wasKeyFrame)
                        {
                            return(new FilePosition(fileName, targetTimeOffset, fileOffset, requestedPosition.MediaType, diff));
                        }
                        else
                        {
                            return(null);
                        }
                    }
                } //while

                //calculate again
                diff = (int)((long)finalTimeOffset - (long)startTimeOffset);
                string.Format("Found keyframe at offset : {0} ms, delta = {1} ms", startTimeOffset, diff).Log(LogLevel.logDetail);
            }
            if (!isStart && fileOffset <= maxOffset)
            {
                fileOffset += asfConfig.AsfPacketSize; //include current packet
            }
            fs.Dispose();

            if (found)
            {
                return(new FilePosition(fileName, targetTimeOffset, fileOffset, requestedPosition.MediaType, diff));
            }
            else
            {
                return(null); //cannot find any earlier keyframe, just return position/file as is
            }
        }
示例#2
0
        internal bool SetOffsetRange(double startOffset, double endOffset, out FilePosition requestStartPosition, out FilePosition requestEndPosition, AsfStreamType streamType)
        {
            requestStartPosition = null;
            requestEndPosition   = null;

            // find the file and offset for the starting time
            requestStartPosition = GetFilePosition(startOffset, streamType, true);

            if (requestStartPosition == null)
            {
                return(false);
            }

            if (endOffset == 0)
            {
                long endFileOffset = EndOffset;
                requestEndPosition = new FilePosition(requestStartPosition.FileName, uint.MaxValue, endFileOffset);
            }
            else
            {
                // find the file and offset for the ending time
                requestEndPosition = GetFilePosition(endOffset, streamType, false);
                if (requestEndPosition == null)
                {
                    return(false);
                }
            }

            StartOffset = requestStartPosition.FileOffset;
            EndOffset   = requestEndPosition.FileOffset;
            Length      = Convert.ToUInt32(EndOffset - StartOffset);
            if (_fileStream != null)
            {
                _fileStream.Dispose();
            }
            _fileStream = null;

            return(true);
        }