예제 #1
0
 public void AddTag(IFlvTag tag)
 {
     this.Tags.Add(tag);
     if (tag.TimeStamp >= this.target)
     {
         this.FinallizeFile();
     }
 }
        public static async Task <StreamMetadata> Parse(StreamRoom room)
        {
            StreamMetadata streamMetadata = new StreamMetadata();

            IFlvStreamProcessor Processor = new FlvStreamProcessor(null, (byte[] data) => new FlvMetadata(data), () => new FlvTag())
                                            .Initialize(null, null, EnabledFeature.ClipOnly, AutoCuttingMode.Disabled);

            Stream _stream = null;
            HttpResponseMessage _response = null;

            var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(2));

            bool success = false;
            bool avc     = false;

            Processor.TagProcessed += (sender, e) =>
            {
                IFlvTag t = e.Tag;

                if (t.TimeStamp > 10 * 1000)
                {
                    success = true;
                    try
                    {
                        cancellationTokenSource.Cancel();
                    }
                    catch (Exception) { }
                    return;
                }

                if (!avc && t.IsVideoKeyframe && t.Profile != -1)
                {
                    avc = true;
                    streamMetadata.Profile = t.Profile;
                    streamMetadata.Level   = t.Level;
                    streamMetadata.AVCDecoderConfigurationRecord = t.Data;
                }
                if (t.TagType == TagType.VIDEO)
                {
                    streamMetadata.TotalSize += t.TagSize;
                }
            };


            try
            {
                using (var client = new HttpClient())
                {
                    client.Timeout = TimeSpan.FromMinutes(2);
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
                    client.DefaultRequestHeaders.UserAgent.Clear();
                    client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36");
                    client.DefaultRequestHeaders.Referrer = new Uri("https://live.bilibili.com");
                    client.DefaultRequestHeaders.Add("Origin", "https://live.bilibili.com");

                    string flv_path = GetPlayUrl(room.Roomid);

                    streamMetadata.FlvHost = new Uri(flv_path).Host;

                    _response = await client.GetAsync(flv_path, HttpCompletionOption.ResponseHeadersRead, cancellationTokenSource.Token);
                }

                if (_response.StatusCode != HttpStatusCode.OK)
                {
                    throw new Exception("StatusCode: " + _response.StatusCode);
                }
                else
                {
                    _stream = await _response.Content.ReadAsStreamAsync();

                    await _ReadStreamLoop();

                    if (!success)
                    {
                        throw new Exception("Timeout");
                    }

                    {
                        var metadata = Processor.Metadata.Meta.Where(x => x.Key.Replace("\0", "").Length != 0).ToDictionary(
                            x => x.Key.Replace("\0", ""),
                            x => (x.Value is string str) ? str.Replace("\0", "") : x.Value
                            );

                        streamMetadata.Width = metadata.ContainsKey("width")
                            ? ((metadata["width"] is int w)
                                ? w
                                : int.Parse(metadata["width"].ToString()))
                            : (metadata.ContainsKey("displayWidth")
                                ? ((metadata["displayWidth"] is int dw)
                                    ? dw
                                    : int.Parse(metadata["displayWidth"].ToString()))
                                : -1);

                        streamMetadata.Height = metadata.ContainsKey("height")
                            ? ((metadata["height"] is int h)
                                ? h
                                : int.Parse(metadata["height"].ToString()))
                            : (metadata.ContainsKey("displayHeight")
                                ? ((metadata["displayHeight"] is int dh)
                                    ? dh
                                    : int.Parse(metadata["displayHeight"].ToString()))
                                : -1);

                        streamMetadata.Fps = metadata.ContainsKey("framerate")
                            ? ((metadata["framerate"] is int f)
                                ? f
                                : int.Parse(metadata["framerate"].ToString()))
                            : (metadata.ContainsKey("fps")
                                ? ((metadata["fps"] is int df)
                                    ? df
                                    : int.Parse(metadata["fps"].ToString()))
                                : -1);

                        streamMetadata.VideoDatarate = metadata.ContainsKey("videodatarate") ? ((metadata["videodatarate"] is int vdr) ? vdr : int.Parse(metadata["videodatarate"].ToString())) : -1;
                        streamMetadata.AudioDatarate = metadata.ContainsKey("audiodatarate") ? ((metadata["audiodatarate"] is int adr) ? adr : int.Parse(metadata["audiodatarate"].ToString())) : -1;

                        streamMetadata.Encoder = metadata.ContainsKey("encoder") ? metadata["encoder"].ToString() : "";

                        streamMetadata.FlvMetadata = metadata;
                    }
                }
            }
            finally
            {
                _CleanupFlvRequest();
            }
            return(streamMetadata);

            async Task _ReadStreamLoop()
            {
                try
                {
                    const int BUF_SIZE = 1024 * 8;
                    byte[]    buffer   = new byte[BUF_SIZE];
                    while (!cancellationTokenSource.Token.IsCancellationRequested)
                    {
                        int bytesRead = await _stream.ReadAsync(buffer, 0, BUF_SIZE, cancellationTokenSource.Token);

                        if (bytesRead != 0)
                        {
                            if (bytesRead != BUF_SIZE)
                            {
                                Processor.AddBytes(buffer.Take(bytesRead).ToArray());
                            }
                            else
                            {
                                Processor.AddBytes(buffer);
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                catch (Exception e)
                {
                    if (e is ObjectDisposedException && cancellationTokenSource.Token.IsCancellationRequested)
                    {
                        return;
                    }

                    throw;
                }
            }

            void _CleanupFlvRequest()
            {
                if (Processor != null)
                {
                    Processor.FinallizeFile();
                    Processor.Dispose();
                    Processor = null;
                }
                _stream?.Dispose();
                _stream = null;
                _response?.Dispose();
                _response = null;
            }
        }