Конференция "Media" » Помогите разобраться с PushSource фильтром
 
  • Neyro © (13.08.15 12:42) [0]
    Есть PushSource, который получает не сжатый PCM звуковой поток по сети. Дальше он передает его на render. Поток приходит с минимальной задержкой в 20мсек, фильтр сразу же выдает его рендеру, а вот рендер упорно накапливает семплы, пока буфер не станет равным 1 сек и только после этого начинает воспроизводить звук. В результате получается ненужная задержка.
    Прочитал, что нужно регистрировать PushSource как LiveSource. Для этого нужно реализовать интерфейсы
    IAMFilterMiscFlags
    и
    IAMLatency
    и устанавливать флаг-признал LiveSource. Все так и сделал. Отладчиком прошелся - граф фильтров вызывает GetPushSourceFlags, я ему выставляю соответствующий флаг AM_PUSHSOURCECAPS_INTERNAL_RM, чтобы рендер не брал на себя синхронизацию потока, а воспроизводил немедленно.
    Результат все тот же: рендер накапливает семплы до 1000мсек, а потом их проигрывает.
    Кто-нибудь может подсказать, как побороть рендер?
    Нужно ли реализовывать интерфейс IID_IReferenceClock? Граф пытается получить его от моего фильтра, а этого интерфейса нет...
  • DVM © (20.08.15 16:18) [1]
    Если не накапливать звук он будет заикаться при воспроизведении скорее всего.
  • Pavia © (20.08.15 21:31) [2]

    > Результат все тот же: рендер накапливает семплы до 1000мсек,
    >  а потом их проигрывает.Кто-нибудь может подсказать, как
    > побороть рендер?

    Время определяет размер буфера. Видимо он у вас большой.
    А для потокового буфера число датчиков Notification и их разброс


    > чтобы рендер не брал на себя синхронизацию потока, а воспроизводил
    > немедленно.

    Рендер не берёт на себя синхронизацию. Хотя и кажется что это так.
    Синхронизация устроена так что каждый фильтр сам ждёт пока следующий в цепочке не освободится.
    Поэтому определяющим является последний фильтр. В данном случае рендер.

    Neyro, вам проще задать вопрос тут:
    http://forum.sources.ru/index.php?showforum=108
  • NeyroSpace (20.08.15 23:10) [3]
    Да, я уже разобрался... Если долго биться головой о бетонную стену, то стена рухнет. В общем ситуация следующая: задержек было 2е. Первая задержка в 0.5 сек была в фильтре захвата. Она там всегда есть по умолчанию. Эта проблема решилась быстро:
    у фильтра захвата находим интерфейс IAMBufferNegotiation и при помощи кода ниже уменьшаем буфер до минимума.

    // The setBufferLatency() procedure.
    procedure TAudioCameras.setBufferLatency(
                   // A buffer negotiation interface pointer.
                   intfBufNegotiate: IAMBufferNegotiation;
                   // The desired latency in milliseconds.
                   bufLatencyMS: WORD
                   // The media type the audio stream is set to.
    //                theMediaType: TMediaType
                   );
    var
       allocProp: _AllocatorProperties;
       wfex: PWaveFormatEx;
    begin
       if not Assigned(intfBufNegotiate) then
         raise Exception.Create('The buffer negotiation IAMBufferNegotiation interface object is unassigned.');

       // Calculate the number of bytes per second using the wave
       // format belonging to the given Media Type.
    //    wfex := getWaveFormat(theMediaType);
       wfex := PWaveFormatEx(FpOutAMMediaType.pbFormat);
       if wfex = nil then
         raise Exception.Create('pOutAMMediaType = nil. Cannt change buffer latency.');

       if wfex.nAvgBytesPerSec = 0 then
         raise Exception.Create('The average bytes per second value for the given Media Type is 0.');

       allocProp.cbAlign := -1;  // -1 means "no preference".
       // Calculate the size of the buffer needed to get the desired
       //  latency in milliseconds given the average bytes per second
       //  of the Media Type's audio format.
       allocProp.cbBuffer := Trunc(wfex.nAvgBytesPerSec * (bufLatencyMS / 1000));
       allocProp.cbPrefix := -1;
       allocProp.cBuffers := -1;

       // Try to set the buffer size to the desired.
       CheckDSError(intfBufNegotiate.SuggestAllocatorProperties(allocProp));
    end;
  • NeyroSpace (20.08.15 23:50) [4]
    Следующая задержка длинной в 1 секунду была на стороне клиента. В стандартном фильтре рендера принимающий буфер всегда устанавливается размером в 1 секунду. Это не зависит от формата медиатипа. И вот тут я уже перепробовал все: перебрал все интерфейсы у рендера, у его iPin - ничего не помогло. Пробовал сам переопределять интерфейс синхронизации времени для все цепочки фильтров, специально сокращать отметки времени между фрэймами - бесполезно. Пробовал менять размеры фрейма - никакой реакции со стороны рендера. Не важно какие фреймы и какого размера и в какое время к нему приходят - он тупо накапливает такое количество фреймов, чтобы заполнить свой внутренний буфер воспроизведения до размера в 1 секунду и только потом начинает воспроизведение. И никак не удавалось повлиять на размер этого буфера. Т.е. по сети звуковые данные прилетают за 20мс, но на рендере они накапливаются целую секунду, прежде, чем воспроизвестись через звуковую карту.
    Самое интересное, что в интернете полно вопросов именно про эту задержку, но ни одного внятного ответа нет. Что там только не советуют... Вплоть до того, что выведи страницу свойств рендера и попробуй там чего-нить "подкрутить".
    Короче, мучился я мучился и понял, что ничего в стандартном рендере уже не исправить!
    Мне все это безобразие надоело, поэтому я взял и написал свой рендер с блэк джэком и шл...ми! За основу был взят пример DirectSound Renderer из каталога примеров DSPack.
    Если обратите внимание на его исходник, то там тоже присутствует предварительный буфер приема длиной в 1,5 сек.

    function TDelphiDSoundRenderer.PrepareReceive(MediaSample: IMediaSample): HResult;
    begin
     Result := inherited PrepareReceive(MediaSample);
     FSignalTime := FSignalTime + (PREBUFFER_SIZE_MS * UNITS div MILLISECONDS);
    end;

    Т.е. входящие семплы от нижестоящего фильтра накапливаются в нем до 1.5 сек, прежде чем быть скопированными в буфер звуковой карты для воспроизведения.
    Поэтому в качестве решения пишем свой рендер, в котором этот буфер сокращаем до минимума. И все полетело без задержек! Никто больше никого не ждет!

    В качестве альтернативы самопальному рендер фильтру еще могу посоветовать воспроизводить звук прямо при приеме из сети вообще без фильтров, используя интерфейс DirectSoundDev: IDirectSound8; Собственно рендер к нему же и обращается. Но тогда у вас не будет цепочки фильтров.
    Надеюсь, эта информация кому-то будет полезна.
 
Конференция "Media" » Помогите разобраться с PushSource фильтром
Есть новые Нет новых   [134427   +38][b:0][p:0]