1

Изучаю вопрос вещания MPEG TS файлов в C# 5.0/.Net Core 3.1 Знаю, что в этих файлах есть временные метки и достать их не проблема. Вопрос пока самый простой. Есть MPEG TS файл. продолжительность этого файла 60100 мсек. Следующий код выстреливает весь файл за примерно 5000 мсек. Нужно чтобы это происходило за 60100 мсек.

static void Main(string[] args)
    {
        string tsFile = @"file.ts";
    byte[] bytes = File.ReadAllBytes(tsFile);

    UdpClient outPutUdpClient = new UdpClient { ExclusiveAddressUse=false};

    IPAddress outPutIp = IPAddress.Parse("192.168.99.239");
    int multicastPort = 1234;

    var localEp = new IPEndPoint(outPutIp, multicastPort);

    outPutUdpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    outPutUdpClient.Ttl = 3;
    outPutUdpClient.Client.Bind(localEp);

    var mcastAddr = IPAddress.Parse("239.1.1.1");

    outPutUdpClient.Connect(mcastAddr, multicastPort);

    for(int i = 1315; i < bytes.Length; i+=1316) // take 7 mpeg(188*7) ts packets per UPD packet
    {
        int begin = i-1315;
        int end = i;

        var sendBytes = bytes[begin..end];

        try
        {
            outPutUdpClient.Send(sendBytes, sendBytes.Length);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }

    }

    Console.WriteLine("Done");
    Console.ReadKey();
}

Можно читать файл по кускам и делать задержки при чтении. Можно прочитать весь файл и делать задержки при отправке. Какой подход для этой задачи будет верным? И как лучше организовать задержку?

Deim
  • 662
  • @aepot это абсолютно не верное предположение для UDP Multicast ts потоков. – Deim Nov 03 '21 at 09:28
  • а если я поставил на паузу, и вы про IGMP? Перенес предложение в ответ. – aepot Nov 03 '21 at 09:32
  • Логика подсказывает мне, что правильнее всего парсить timestamp'ы из MPEG TS пакетов и отправлять их в правильные моменты времени согласно timestamp'ам (но сам я так делать не умею). // Стоит отметить, что битрейт при этом вовсе не обязательно должен быть постоянным, если у исходного видео битрейт сам по себе переменный – andreymal Nov 09 '21 at 14:47
  • @andreymal в моём случае исходники были в CBR. Вещать TS по PCR меткам это следующий этап))). Если файл большой, то разумеется выгоднее читать по частям и не помещать весь файл в память. – Deim Nov 09 '21 at 14:56
  • Ради интереса попробовал замерить время между UDP-пакетами на моём IPTV (как раз новости по Первому каналу начались) — получился такой график: https://i.stack.imgur.com/PYpa5.png (всего 30399 пакетов по 1358 байт) Не уверен, как его правильно интерпретировать, но, похоже, сервер старается адаптировать промежутки отправки под переменный битрейт видеопотока (в общем-то как вы в конце своего ответа и написали) – andreymal Nov 09 '21 at 15:22
  • @andreymal да, похоже на то. – Deim Nov 09 '21 at 15:27

1 Answers1

1

Провёл некоторые изыскания на эту тему. Результаты ниже. Замеры проводились с помощью анализатора от Dektec StreamXpert v 2.2.1

  • Вариант 1. отправлять UDP пакеты пачками через определённый промежуток времени:

         var cnt = 0;
    
     for (int i = 0; i < iteration; i++)
     {
         var sendBytes = new byte[188 * 7];
    
         cnt++;
    
         if (cnt >= 57) // через каждые 57 пакетов - задержка в 1 мс.
         {
             Thread.Sleep(1);
             cnt = 0;
         }
    
    
         for (int j = 0; j < 7; j++)
         {                    
             Buffer.BlockCopy(packets[7 * i + j].bytes, 0, sendBytes, j * 188, 188);
         }
    
         outPutUdpClient.Send(sendBytes, 188 * 7);
     }
    

На анализаторе получаем такую картинку: введите сюда описание изображения битрейт в виде пилы, как следствие ошибки TR101290 2-го приоритета связанные с PCR.

  • Вариант 2. Использовать таймер и через определённые промежутки времени вызывать событие которое отправит заранее рассчитанную пачку байт:

             timer = new System.Timers.Timer();
             timer.Interval = 10; 
             timer.AutoReset = true;
             timer.Elapsed += Timer_Elapsed;
             timer.Enabled = true;
    

При 10 мс картинка на анализаторе становится чуть лучше: введите сюда описание изображения При разрешении 1 мс стандартный таймер перестаёт нормально работать. Общий битрейт падает. В причины такого поведения не углублялся. введите сюда описание изображения

На анализаторе идеальная прямая: введите сюда описание изображения

Вывод. Думаю, что запустить вещание MPEG TS потока с ровным битрейтом можно только с помощью MultiMedia timer. Если есть другие варианты, то просьба поделиться.

ps. на низких битрейтах работает и стандартный таймер, но при битрейтах 30+ Мбит/сек его уже не хватает. Для того, чтобы всё было по фэн-шую нужно брать PCR метки из потока и на их основании делать расчёт количества отправляемых пакетов за единицу времени. Текущий вариант будет работать только с потоком с постоянным битрейтом (CBR)

Deim
  • 662