Должны ли мы возвращать полные буферы каждый раз, когда вызывается обратный вызов AVIO `read_packet ()` из FFMPEG?

#c #ffmpeg #callback

#c #ffmpeg #обратный вызов

Вопрос:

Я выделяю контекст AVIO с моей собственной read_packet() реализацией. Только моя реализация такова, что я могу вернуться с count меньшим, чем требуемый ввод buf_size . Это разрешено? Или мы должны заполнять буфер как можно больше при каждом вызове read_packet() функции выхода?

 // initialization
    [...snip...]
    m_avio_context.reset(avio_alloc_context(
                          avio_buffer
                        , avio_buffer_size
                        , 0             // write flag
                        , this          // opaque
                        , amp;FFMPEGDecoder::decoder_read_static
                        , nullptr       // write func.
                        , nullptr));    // seek func.
    [...snip...]

// implementation of static function
int FFMPEGDecoder::decoder_read_static(void * opaque, std::uint8_t * buf, int size)
{
    return reinterpret_cast<FFMPEGDecoder *>(opaque)->decoder_read(buf, size);
}

// the actual read_packet()
int FFMPEGDecoder::decoder_read(std::uint8_t * buf, int size)
{
    // in flushing mode, we won't receive any more packets
    //
    if(m_flushing)
    {
        return 0;
    }

    // m_packet is my own packet implementation (an std::vector<>)
    //
    while(m_packet == nullptr
       || static_cast<std::size_t>(m_read_pos) >= m_packet->size())
    {
        if(!m_incoming_packets.pop_front(m_packet, -1))
        {
            return 0;
        }
        if(m_packet->is_flush())
        {
            m_flushing = true;
            return 0;
        }
        m_read_pos = 0;
    }

    // the number of bytes to copy size `size` or less if there are
    // less bytes available in my m_packet
    //
    int const copy(std::min(static_cast<std::size_t>(size), m_packet->size() - m_read_pos));

    memcpy(buf, m_packet->data().data()   m_read_pos, copy);

    m_read_pos  = copy;

    return copy;
}
 

Я не ищу способ заполнить буфер, я собираюсь реализовать его таким образом сейчас. Я ищу подтверждение (или нет), что библиотеки FFMPEG не способны принимать меньше size байтов buf при read_packet() вызове нашего.

Вы знаете?

Комментарии:

1. Я размышляю здесь, но при декодировании видео, особенно в (живых) потоках, вы можете заранее не знать, что будет поступать из следующего потока, это может зависеть от содержимого текущих декодированных пакетов (например, В транспортном потоке могут быть необязательные заголовки, метаданные и т. Д.). Я не знаю, но для меня логично, чтобы «размер» был максимальным или около того, потому что фактическое количество зависит от декодирования и конкретной структуры данных, обнаруженных в необработанном вводе. Подсказкой для меня также является эта строка: ffmpeg.org/doxygen/3.1/avio__reading_8c_source.html 45:buf_size = FFMIN(buf_size, bd->размер)

2. Однако этот код заканчивается один раз buf_size = 0 , что означает «конец файла» (т. Е. Они выполняются через один буфер; в моем случае я выполняю много буферов). Но, похоже, моя проблема была в другом месте, где я использовал поле неправильного размера (так много размеров!)

3. Что-то еще, что кажется связанным с документами PyAV (это оболочка, но низкоуровневая): pyav.org/docs/develop/api /… см. Поле «задержка»: «Кодер или декодер требует промывки с нулевым вводом в конце, чтобы выдать полный и правильный вывод. (…) Декодеры: декодеримеет ненулевую задержку и должен быть передан с помощью avpkt->data = NULL, avpkt-> size = 0 в конце, чтобы получить отложенные данные до тех пор, пока декодер больше не будет возвращать кадры (…) Кодировщик должен быть передан с нулевыми данными в конце кодирования, пока кодировщикбольше не возвращает данные.

4. Также этот пример синтаксического анализа: pyav.org/docs/develop/cookbook/basics.html#parsing codec = av.CodecContext.create(‘h264’, ‘r’) при значении True: фрагмент = fh.read(1 << 16) пакеты = codec.parse(фрагмент) печать («Проанализированы {} пакеты из {} байт:».формат (len (пакеты), len (фрагмент))) для пакета в пакетах: (…) Файл считывается порциями по 64 КБ, пакеты анализируются и т.д., конечный может быть <64 КБ. Я предполагаю, что контекст кодека отслеживает совпадения между последовательными фрагментами и сохраняет его в другом буфере. В любом случае он должен запоминать текущие ключевые кадры и т. Д.

5. @Twenkid Да, конечный автомат сложный… Моя проблема была не в конце, это произошло бы по пути, появляются некоторые пробелы, когда звук переходит в 0s. Я мог бы еще раз протестировать и посмотреть, работает ли он сейчас без моего дополнительного цикла … похоже, что это сработает, но я думаю, что это также может зависеть от используемого декодера. С WAV-файлом это может работать нормально, с AAC или OGG это может привести к сбою… кто знает. Это плохо документировано.