Как задать битрейт выходного потока UDP

Изучаю вопрос вещания 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();
    }

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


Ответы (1 шт):

Автор решения: Deim

Провёл некоторые изыскания на эту тему. Результаты ниже. Замеры проводились с помощью анализатора от 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)

→ Ссылка