public Track(TrackInfo trackInfo) { this.TrackInfo = trackInfo; this.DownloadedChunkCount = 0; }
// Modifies track in place, and appends to mediaSamples. // Returns null on network failure or empty file, otherwise it returns a non-empty array. // The chunk file contents are returned, and are not saved to disk. internal static byte[] DownloadChunk(TrackInfo trackInfo, IList<MediaSample> mediaSamples, ulong chunkStartTime, string manifestParentPath, bool isLive, out ulong nextStartTime) { nextStartTime = 0; // Set even if null is returned. string chunkUrl = trackInfo.Stream.GetChunkUrl(trackInfo.Bitrate, chunkStartTime); // TODO: Move TrackInfo away from Track, keep only fields necessary here, excluding ChunkList. byte[] downloadedBytes; // Will be set below. if (manifestParentPath != null) { // It was a local manifest, so read the chunk from a local file. if (!chunkUrl.StartsWith(LOCAL_URL_PREFIX)) { throw new Exception("ASSERT: Missing local URL prefix."); } // Example chunk URL: "http://local/QualityLevels(900000)/Fragments(video=0)". // TODO: Maybe this needs some further unescaping of %5A etc. (can be tested locally). string chunkDownloadedPath = manifestParentPath + Path.DirectorySeparatorChar + chunkUrl.Substring(LOCAL_URL_PREFIX.Length).Replace('/', Path.DirectorySeparatorChar); using (FileStream fileStream = new FileStream(chunkDownloadedPath, FileMode.Open)) { downloadedBytes = ReadFileStream(fileStream); } if (downloadedBytes.Length == 0) { Console.WriteLine(); Console.WriteLine("Local chunk file empty: " + chunkDownloadedPath); return null; } } else { // Download from the web. WebClient webClient = new WebClient(); try { // TODO: What's the timeout on this? downloadedBytes = webClient.DownloadData(chunkUrl); } catch (WebException) { Thread.Sleep(isLive ? 4000 : 2000); try { downloadedBytes = webClient.DownloadData(chunkUrl); } catch (WebException) { Thread.Sleep(isLive ? 6000 : 3000); try { downloadedBytes = webClient.DownloadData(chunkUrl); } catch (WebException) { // It's an acceptable behavior to stop downloading live streams after 10 seconds. // If it's really live, there should be a new chunk update available every 10 seconds. Console.WriteLine(); Console.WriteLine("Error downloading chunk " + chunkUrl); return null; } } } } if (downloadedBytes.Length == 0) { Console.WriteLine(); Console.WriteLine("Chunk empty: " + chunkUrl); return null; } Fragment fragment = new Fragment(downloadedBytes, 0, downloadedBytes.Length); // This appends to mediaSamples. nextStartTime = ParseFragment(fragment, mediaSamples, trackInfo.Stream.Type, chunkStartTime); if (nextStartTime <= chunkStartTime) { throw new Exception("Found empty chunk."); } return downloadedBytes; }