Example #1
0
 // Appends to `samples'.
 // Returns nextStartTime.
 private static ulong ParseFragment(Fragment fragment, IList<MediaSample> samples, MediaStreamType type,
     ulong chunkStartTime)
 {
     // A fragment is a ``chunk'' (with a corresponding <c d=....> in its duration) in the ISM manifest file.
       TrackFragmentBox traf = fragment.moof.traf;
       if (traf.tfxd != null) {
     chunkStartTime = traf.tfxd.FragmentAbsoluteTime;
       }
       ulong nextStartTime = 0uL;
       if (traf.tfrf != null && traf.tfrf.Array.Length > 0u) {
     nextStartTime = traf.tfrf.Array[0].FragmentAbsoluteTime;
       }
       long sampleOffset = fragment.mdat.Start;
       uint defaultSampleSize = traf.tfhd.default_sample_size;
       uint sampleSize = defaultSampleSize;
       uint defaultSampleDuration = traf.tfhd.default_sample_duration;
       uint duration = defaultSampleDuration;
       ulong totalDuration = 0;
       uint sampleCount = traf.trun.sample_count;
       TrackRunBox.Element[] array = defaultSampleSize == 0u || defaultSampleDuration == 0u ? traf.trun.array : null;
       for (uint i = 0; i < sampleCount; ++i) {
     if (defaultSampleSize == 0u) {
       sampleSize = array[i].sample_size;
     }
     if (defaultSampleDuration == 0u) {
       duration = array[i].sample_duration;
     }
     // We add a few dozen MediaSample entries for a chunk.
     samples.Add(new MediaSample(sampleOffset, (int)sampleSize, chunkStartTime,
                             /*isKeyFrame:*/i == 0 || type == MediaStreamType.Audio));
     chunkStartTime += (ulong)duration;
     totalDuration += (ulong)duration;
     sampleOffset += sampleSize;
       }
       return nextStartTime != 0uL ? nextStartTime : chunkStartTime;
 }
Example #2
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;
 }