Я занимаюсь разработкой мультимедийного приложения, которое транслирует видео и аудио по RTSP с использованием библиотеки liveMedia.
Я читаю необработанные видеокадры с камеры, кодирую их с помощью libx264, сохраняю их в tbb :: concurrent_queue и запускаю RTSP-сервер. Я использую DynamicRTSPServer.cpp и live555MediaServer.cpp в качестве примера для создания моего модуля RTSP, и у меня есть проблема — один поток (который выполняет BasicTaskScheduler :: doEventLoop) использует слишком много процессорного времени — более 80-90% одного ядра процессора (у меня есть Intel Dual-Core T3100).
А для моего видеопотока у меня большая задержка, и VLC не может воспроизводить видеопоток (аудиопоток воспроизводится нормально) с ошибками:
основное предупреждение: изображение слишком поздно для отображения (пропущено 3780 мс)
Ошибка avcodec: более 5 секунд позднего видео -> сброс кадра (компьютер работает слишком медленно?)
Когда я отключаю аудиоподсессию, я также использую процессор, но VLC может нормально воспроизводить видеопоток.
Я прочитал файл журнала сервера и обнаружил, что у меня много неудачных попыток чтения новых данных из пустой очереди.
Это фрагмент моего файла журнала (посмотрите на время отладочных сообщений — это другой вызов FramedSource :: doGetNextFrame)
[10:49:7:621]: videoframe readed. size: 0
[10:49:7:622]: videoframe readed. size: 0
[10:49:7:622]: videoframe readed. size: 0
[10:49:7:622]: videoframe readed. size: 0
[10:49:7:622]: videoframe readed. size: 0
[10:49:7:622]: videoframe readed. size: 0
[10:49:7:623]: videoframe readed. size: 0
[10:49:7:623]: videoframe readed. size: 0
[10:49:7:623]: videoframe readed. size: 0
[10:49:7:623]: videoframe readed. size: 0
[10:49:7:623]: videoframe readed. size: 0
[10:49:7:624]: videoframe readed. size: 0
Мой видеопоток имеет низкую частоту кадров (камера может только 8 кадров в секунду или менее), и когда вызывается doGetNextFrame, в моем буфере еще нет закодированного кадра в очереди.
У меня есть следующий стек вызовов при этих попытках:
ConcurrentQueueBuffer::doGetNextFrame()
FramedSource::getNextFrame(unsigned char* to, unsigned maxSize,
afterGettingFunc* afterGettingFunc,
void* afterGettingClientData,
onCloseFunc* onCloseFunc,
void* onCloseClientData)
StreamParser::ensureValidBytes1(unsigned numBytesNeeded)
StreamParser::ensureValidBytes(unsigned numBytesNeeded)
StreamParser::test4Bytes()
H264VideoStreamParser::parse()
MPEGVideoStreamFramer::continueReadProcessing()
MPEGVideoStreamFramer::continueReadProcessing(void* clientData,
unsigned char* /*ptr*/, unsigned /*size*/,
struct timeval /*presentationTime*/)
StreamParser::afterGettingBytes1(unsigned numBytesRead, struct timeval presentationTime)
StreamParser::afterGettingBytes(void* clientData,
unsigned numBytesRead,
unsigned /*numTruncatedBytes*/,
struct timeval presentationTime,
unsigned /*durationInMicroseconds*/)
FramedSource::afterGetting(FramedSource* source)
AlarmHandler::handleTimeout()
...
Я пытался изменить логику буфера и блокировать поток, пока кодировщик дает мне новые кадры, но в этом случае у меня также очень большая задержка для моего аудиопотока.
Я установил несколько задержек при запуске сервера для сохранения большего количества данных в буфере, но livemedia считывает данные из буфера быстрее, чем кодировщик кодирует их 🙁
В чем может быть причина этой проблемы? А как liveMedia обнаруживает частоту попыток чтения из FramedSource?
Мой H264BufferMediaSubsession наследует H264VideoFileServerMediaSubsession liveMedia и переопределяет только виртуальный метод createNewStreamSource (), где я создаю FramedSource, который будет считывать данные из моего буфера.
Задача ещё не решена.
Других решений пока нет …