Ответ 1
Я никогда не использовал FLV или не изучал видеоформаты.
Большинство форматов файлов структурированы, особенно видеоформаты. Они содержат кадры (т.е. Полный или частичный скриншоты в зависимости от формата сжатия).
Вам действительно должно быть повезло, если вам удастся попасть в конкретный кадр при запуске потоковой передачи новому подписчику. Следовательно, когда они начинают получать поток, они не могут идентифицировать формат, поскольку кадр является частичным.
Вы можете прочитать больше кадров FLV в статье в википедии. Это, скорее всего, ваша проблема.
Простая попытка состояла бы в том, чтобы попытаться сохранить исходный заголовок, который вы получаете с потокового сервера, когда подключается первый абонент.
Что-то вроде:
static byte _header = new byte[9]; //signature, version, flags, headerSize
public void YourStreamMethod()
{
int bytesRec = handler.Receive(bytes);
if (!_headerIsStored)
{
//store header
Buffer.BlockCopy(bytes, 0, _header, 0, 9);
_headerIsStored = true;
}
}
.., который позволяет отправить заголовок следующему подключающемуся абоненту:
private async Task WriteToStream( Stream arg1, HttpContent arg2, TransportContext arg3 )
{
// send the FLV header
arg1.Write(_header, 0, 9);
Startup.AddSubscriber( arg1 );
await Task.Yield();
}
Сделав это, молись, чтобы приемник проигнорировал частичные кадры. Если это не так, вам нужно проанализировать поток, чтобы определить, где находится следующий кадр.
Для этого вам нужно сделать что-то вроде этого:
- Создайте переменную
BytesLeftToNextFrame
. - Сохранить полученный пакетный заголовок в буфере
- Преобразовать биты размера полезной нагрузки в int
- Reset
BytesLeftToNextFrame
к анализируемому значению - Обратный отсчет до следующего раза, когда вы должны прочитать заголовок.
Наконец, когда новый клиент подключается, не запускайте потоковое вещание, пока не узнаете, что приходит следующий кадр.
Псевдокод:
var bytesLeftToNextFrame = 0;
while (true)
{
bytes = new byte[8024000];
int bytesRec = handler.Receive(bytes);
foreach (var subscriber in Startup.Subscribers.ToList())
{
var theSubscriber = subscriber;
try
{
if (subscriber.IsNew && bytesLeftToNextFrame < bytesRec)
{
//start from the index where the new frame starts
await theSubscriber.WriteAsync( bytes, bytesLeftToNextFrame, bytesRec - bytesLeftToNextFrame);
subscriber.IsNew = false;
}
else
{
//send everything, since we've already in streaming mode
await theSubscriber.WriteAsync( bytes, 0, bytesRec );
}
}
catch
{
Startup.Subscribers.Remove(theSubscriber);
}
}
//TODO: check if the current frame is done
// then parse the next header and reset the counter.
}