Пример #1
0
        private bool SetAsfFileProperties(AsfFileConfiguration asfConfig, FileInfo fi)
        {
            bool isKeyframe           = false;
            uint startTimeOffsetVideo = 0;
            uint endTimeOffsetVideo   = 0;
            uint startTimeOffsetAudio = 0;
            uint endTimeOffsetAudio   = 0;

            bool hasVideoStream = asfConfig.ImageWidth > 0;


            using (FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                fs.Seek(asfConfig.AsfHeaderSize, SeekOrigin.Begin);
                long maxOffset = asfConfig.AsfHeaderSize + (asfConfig.AsfPacketCount - 1) * asfConfig.AsfPacketSize;
                if (maxOffset < 0)
                {
                    return(false);
                }

                if (hasVideoStream)
                {
                    if (!FindNextTimeOffset(asfConfig, fs, out isKeyframe, ref startTimeOffsetVideo, asfConfig.AsfVideoStreamId))
                    {
                        return(false);
                    }
                    fs.Seek(asfConfig.AsfHeaderSize, SeekOrigin.Begin);
                }


                if (!FindNextTimeOffset(asfConfig, fs, out isKeyframe, ref startTimeOffsetAudio, asfConfig.AsfAudioStreamId))
                {
                    return(false);
                }

                //now position at last packet
                if (hasVideoStream)
                {
                    fs.Seek(maxOffset, SeekOrigin.Begin);
                    while (!FindNextTimeOffset(asfConfig, fs, out isKeyframe, ref endTimeOffsetVideo, asfConfig.AsfVideoStreamId, false))
                    {
                        maxOffset -= asfConfig.AsfPacketSize;
                        if (maxOffset <= asfConfig.AsfHeaderSize)
                        {
                            return(false);
                        }
                        fs.Seek(maxOffset, SeekOrigin.Begin);
                    }
                }

                //now position at last packet
                fs.Seek(maxOffset, SeekOrigin.Begin);

                while (!FindNextTimeOffset(asfConfig, fs, out isKeyframe, ref endTimeOffsetAudio, asfConfig.AsfAudioStreamId, false))
                {
                    maxOffset -= asfConfig.AsfPacketSize;
                    if (maxOffset <= asfConfig.AsfHeaderSize)
                    {
                        return(false);
                    }
                    fs.Seek(maxOffset, SeekOrigin.Begin);
                }
            }

            double fileDuration = 0;

            if (hasVideoStream)
            {
                fileDuration = endTimeOffsetVideo - startTimeOffsetVideo;
            }
            else
            {
                fileDuration = endTimeOffsetAudio - startTimeOffsetAudio;
            }

            fileDuration /= 1000; //set to milisecond resolution

            StartTimeOffsetVideo = startTimeOffsetVideo;
            EndTimeOffsetVideo   = endTimeOffsetVideo;
            StartTimeOffsetAudio = startTimeOffsetAudio;
            EndTimeOffsetAudio   = endTimeOffsetAudio;

            var dataObject = GetAsfObject <AsfDataObject>();

            EndOffset = dataObject.Position + dataObject.Size;
            MediaType = endTimeOffsetVideo > 0 ? FileMediaType.Video : FileMediaType.Audio;

            return(true);
        }
Пример #2
0
        /// <summary>
        /// Correct presentation and send time stamps based on the stream info
        /// <param name="configuration">The ASF configuration</param>
        /// <param name="asfStreamInfo">The stream info</param>
        /// </summary>
        public void SetFollowup(AsfFileConfiguration configuration, AsfStreamInfo asfStreamInfo)
        {
            Int64 packetSendTime = (Int64)SendTime - asfStreamInfo.StartSendTime;

            if (packetSendTime - AsfConstants.ASF_SEND_SAFTEY_THRESHOLD > 0)
            {
                packetSendTime -= AsfConstants.ASF_SEND_SAFTEY_THRESHOLD;
            }
            else
            {
                packetSendTime = 0;
            }

            SendTime = (uint)packetSendTime;

            //base payload on packet send time, add delta to zero based send time
            for (int i = 0; i < Payload.Count; i++)
            {
                Int64 payloadPresentationTime = (Int64)Payload[i].PresentationTime - asfStreamInfo.StartTimeOffset;
                if (payloadPresentationTime < _asfConfig.AsfPreroll)
                {
                    //an audio payload before the preroll must be eliminated, in this case we assign it a private stream id
                    if (Payload[i].StreamId == configuration.AsfAudioStreamId && asfStreamInfo.StreamType != AsfStreamType.asfUnaltered)
                    {
                        payloadPresentationTime = SendTime + _asfConfig.AsfPreroll;
                        MovePayloadPrivate(Payload[i], (uint)payloadPresentationTime);
                    }
                    else
                    {
                        //set the time slightly before the preroll time - not used by renderer, but decoded so first frame (seek point) can be delta frame
                        payloadPresentationTime = asfStreamInfo.StreamType == AsfStreamType.asfImage ? (_asfConfig.AsfPreroll - 100) : _asfConfig.AsfPreroll;
                    }
                }


                //remove unnecesscary audio data for image stream, that means only one stream is remaining which sets the timeline
                if (asfStreamInfo.StreamType == AsfStreamType.asfImage && Payload[i].StreamId == configuration.AsfAudioStreamId)
                {
                    MovePayloadPrivate(Payload[i], SendTime + _asfConfig.AsfPreroll);
                }

                //Packet Sendtime must be earlier than Payload presentation times
                if (payloadPresentationTime < SendTime)
                {
                    SendTime = Math.Max((uint)payloadPresentationTime, asfStreamInfo.MinPacketSendTime);
                }

                SetPayloadPresentationTime(Payload[i], (uint)payloadPresentationTime);

                if ((asfStreamInfo.StreamType != AsfStreamType.asfUnaltered) && asfStreamInfo.StreamType != AsfStreamType.asfImage && Payload[i].PresentationTime > _asfConfig.AsfPreroll && Payload[i].PresentationTime - _asfConfig.AsfPreroll > (asfStreamInfo.EndTimeOffset - asfStreamInfo.StartTimeOffset))
                {
                    //Crop both audio and video at the end of the segment
                    payloadPresentationTime = (asfStreamInfo.EndTimeOffset - asfStreamInfo.StartTimeOffset) + _asfConfig.AsfPreroll;
                    MovePayloadPrivate(Payload[i], (uint)payloadPresentationTime);
                }

                //Handle media object id's: must be consecutive, starting at zero, roll over at 255
                uint maxPresentationTime = 0;
                asfStreamInfo.MaxPresentationTime.TryGetValue(Payload[i].StreamId, out maxPresentationTime);
                if (maxPresentationTime < Payload[i].PresentationTime)
                {
                    asfStreamInfo.MaxPresentationTime[Payload[i].StreamId] = Payload[i].PresentationTime;
                }

                if ((asfStreamInfo.MediaObjectId[Payload[i].StreamId] == 0 && asfStreamInfo.PrevMediaObjectId[Payload[i].StreamId] == 0) || asfStreamInfo.PrevMediaObjectId[Payload[i].StreamId] != Payload[i].MediaObjectNumber)
                {
                    asfStreamInfo.MediaObjectId[Payload[i].StreamId]++;
                }

                asfStreamInfo.PrevMediaObjectId[Payload[i].StreamId] = Payload[i].MediaObjectNumber;
                SetMediaObjectNumber(i, asfStreamInfo.MediaObjectId[Payload[i].StreamId]);
            }

            //the send time of the next packet must be larger or equal than the send time of the current packet, keep track of send time
            asfStreamInfo.MinPacketSendTime = SendTime;
        }
Пример #3
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
            }
        }