Began parsing Threemedia OTT fragments.
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 1m14s

This commit is contained in:
feyris-tan 2026-06-28 12:37:47 +02:00
parent 6e5bf2d2db
commit 124bc001aa
6 changed files with 224 additions and 1 deletions

View File

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.ThreemediaOtt
{
internal abstract class ThreemediaBaseStream : Stream
{
public override void Flush()
{
throw new NotSupportedException();
}
public override long Position
{
get
{
return _internalPosition;
}
set
{
if (value > calculatedLength)
{
throw new ArgumentOutOfRangeException(nameof(value), value, String.Format("This stream is capped at {0}", calculatedLength));
}
Seek(value, SeekOrigin.Begin);
}
}
public override long Seek(long offset, SeekOrigin origin)
{
long newPosition;
switch (origin)
{
case SeekOrigin.Begin:
newPosition = offset;
break;
case SeekOrigin.Current:
newPosition = Position + offset;
break;
case SeekOrigin.End:
newPosition = Length + offset;
break;
default:
throw new NotImplementedException(String.Format("Unknown seek operation: {0}", origin));
}
if (newPosition < 0 || newPosition > calculatedLength)
{
throw new IOException("An attempt was made to move the file pointer before the beginning or past the end of the stream.");
}
SeekHook();
return newPosition;
}
protected abstract void SeekHook();
private bool lengthSet;
private long calculatedLength;
public override void SetLength(long value)
{
if (lengthSet)
{
throw new NotSupportedException();
}
else
{
calculatedLength = value;
lengthSet = true;
}
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override bool CanRead => true;
public override bool CanSeek => true;
public override bool CanWrite => false;
public override long Length => calculatedLength;
protected long _internalPosition;
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper.IO;
using skyscraper8.Ietf.FLUTE;
namespace skyscraper8.ThreemediaOtt
@ -52,5 +53,41 @@ namespace skyscraper8.ThreemediaOtt
return true;
}
public ThreemediaContentFragmentStream CreateStream()
{
byte[] lastBlock = blocks[blocks.Length - 1];
MemoryStream lastBlockStream = new MemoryStream(lastBlock, false);
lastBlockStream.Position = lastBlockStream.Length - 8;
int footerLength = (int)lastBlockStream.ReadUInt32BE();
int footerOffset = (int)(lastBlockStream.Length - 8 - footerLength);
Dictionary<string, string> footer = ExtractFooter(lastBlock, footerLength, footerOffset);
int[] blockSizes = Array.ConvertAll(blocks, (x) => x.Length);
blockSizes[blocks.Length - 1] = footerOffset;
ThreemediaContentFragmentStream result = new ThreemediaContentFragmentStream(blocks, blockSizes, footer);
throw new NotImplementedException();
}
private Dictionary<string, string> ExtractFooter(byte[] lastBlock, int footerLength, int footerOffset)
{
MemoryStream ms = new MemoryStream(lastBlock, footerOffset, footerLength, false);
StreamReader sr = new StreamReader(ms, Encoding.ASCII);
Dictionary<string, string> result = new Dictionary<string, string>();
while (!sr.EndOfStream)
{
string? line = sr.ReadLine();
int seperator = line.IndexOf(':');
string key = line.Substring(0, seperator);
string value = line.Substring(seperator + 1);
result.Add(key, value);
}
return result;
}
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.ThreemediaOtt
{
internal class ThreemediaContentFragmentStream : ThreemediaBaseStream
{
private readonly byte[][] _blocks;
private readonly int[] _blockSizes;
private int _currentBlockIndex;
private int _currentBlockPosition;
public ThreemediaContentFragmentStream(byte[][] blocks, int[] blockSizes, Dictionary<string, string> footer)
{
_blocks = blocks ?? throw new ArgumentNullException(nameof(blocks));
_blockSizes = blockSizes ?? throw new ArgumentNullException(nameof(blockSizes));
if (_blocks.Length != _blockSizes.Length)
{
throw new ArgumentException("Blocks and blockSizes arrays must have the same length.");
}
// Calculate total stream length based on the valid payloads
SetLength(_blockSizes.Sum(x => (long)x));
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
protected override void SeekHook()
{
long remainingOffset = _internalPosition;
_currentBlockIndex = 0;
_currentBlockPosition = 0;
while (_currentBlockIndex < _blocks.Length && remainingOffset > 0)
{
int blockSize = _blockSizes[_currentBlockIndex];
if (remainingOffset >= blockSize)
{
remainingOffset -= blockSize;
_currentBlockIndex++;
}
else
{
_currentBlockPosition = (int)remainingOffset;
remainingOffset = 0;
}
}
}
}
}

View File

@ -107,7 +107,12 @@ namespace skyscraper8.ThreemediaOtt
return;
}
throw new NotImplementedException();
ThreemediaSessionStream stream = selectedSession.CreateStream();
FileStream fs = File.OpenWrite("test.bin");
stream.CopyTo(fs);
fs.Flush(true);
fs.Close();
}
public bool StopProcessingAfterThis()

View File

@ -55,5 +55,12 @@ namespace skyscraper8.ThreemediaOtt
fragments = null;
}
public ThreemediaSessionStream CreateStream()
{
ThreemediaContentFragmentStream[] fragmentStreams = Array.ConvertAll(fragments, (x) => x.CreateStream());
ThreemediaSessionStream stream = new ThreemediaSessionStream(fragmentStreams);
return stream;
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.ThreemediaOtt
{
internal class ThreemediaSessionStream : ThreemediaBaseStream
{
public ThreemediaSessionStream(ThreemediaContentFragmentStream[] fragmentStreams)
{
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
protected override void SeekHook()
{
throw new NotImplementedException();
}
}
}