«3.4.3 Инкапсуляция исходных файлов H264 в формат MP4» в книге «Практика разработки FFmpeg: от нулевых основ к короткому видео в Интернете» рассказывает, как инкапсулировать голые потоки H.264 в файлы MP4. Так как же голый поток H.264, передаваемый по сети, получает видеоформат на принимающей стороне? В предыдущей статье указывалось, что поток H.264 должен начинаться с «Кадр SPS → Кадр PPS → Кадр IDR». Далее давайте проверим, действительно ли это так.
Здесь используется анализатор H264, написанный Лэй Сяохуа и Лэй Шеном. Хочу отдать должное Лэй Шену. Небольшая программа, написанная Лэй Шеном 10 лет назад, до сих пор проста в использовании. Откройте анализатор H264. Начальный интерфейс программного обеспечения показан ниже:
Нажмите кнопку «Открыть» в правой части панели пути к файлу, выберите файл чистого потока H.264 во всплывающем диалоговом окне файла, а затем нажмите кнопку «Пуск» в правом нижнем углу интерфейса. Запустится анализатор. для анализа формата содержимого файла H264. После анализа Интерфейс результатов показан ниже:
Из результатов анализа видно, что первые три кадра голого потока H.264 действительно представляют собой «кадр SPS → кадр PPS → кадр IDR». Щелкните кадр в списке, и подробная информация о поле кадра отобразится в правой части интерфейса.
Конечно, анализатор может читать только файлы чистого потока H.264. Если анализатору будет предложено прочитать файл MP4, он не сможет нормально прочитать информацию каждого кадра. Так как же сервер потоковой передачи преобразует файлы MP4 в чистые потоки H.264? Если взять в качестве примера ZLMediaKit, он выполняет специальную обработку при вставке I-кадров в последовательность отправки. Как только появляется I-кадр, он автоматически вставляет кадры конфигурации, такие как SPS и PPS. Конкретный код находится в ext-codec/H264.cpp платформы ZLMediaKit. Проверьте функцию H264Track::inputFrame_l исходного кода и найдите следующий фрагмент кода. Видно, что программа вызывает функцию InsertConfigFrame после оценки ключа. рамка.
// Определите, является ли это I-кадром, И если да, то определите, был ли ранее вставлен конфиг-фрейм, Если он был вставлен ранее, он не будет вставлен снова.
if (frame->keyFrame() && !_latest_is_config_frame) {
insertConfigFrame(frame); // Вставка кадров SPS и кадров PPS
}
if(!frame->dropAble()){
_latest_is_config_frame = false;
}
ret = VideoTrack::inputFrame(frame);
Найдите код определения функции InsertConfigFrame следующим образом. Конечно же, содержимое функции последовательно вставляет кадр SPS и кадр PPS:
// Вставка кадров SPS и кадров PPS
void H264Track::insertConfigFrame(const Frame::Ptr &frame) {
if (!_sps.empty()) { // Вставить рамку SPS
auto spsFrame = FrameImp::create<H264Frame>();
spsFrame->_prefix_size = 4;
spsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
spsFrame->_buffer.append(_sps);
spsFrame->_dts = frame->dts();
spsFrame->setIndex(frame->getIndex());
VideoTrack::inputFrame(spsFrame);
}
if (!_pps.empty()) { // Вставить рамку PPS
auto ppsFrame = FrameImp::create<H264Frame>();
ppsFrame->_prefix_size = 4;
ppsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
ppsFrame->_buffer.append(_pps);
ppsFrame->_dts = frame->dts();
ppsFrame->setIndex(frame->getIndex());
VideoTrack::inputFrame(ppsFrame);
}
}
Видно, что ZLMediaKit вставляет дополнительные кадры SPS и кадры PPS перед каждым ключевым кадром, чтобы гарантировать, что голый поток H.264 поддерживает формирование «кадр SPS → кадр PPS → кадр IDR». Если SPS и PPS не добавлены, клиент сообщит о следующей ошибке при получении потоков:
[NULL @ 0000022ed7782540] non-existing PPS 0 referenced
Только с добавлением SPS и PPS клиент может нормально извлекать и анализировать данные, а также нормально рендерить видеоизображения. 更多详细的FFmpegИнформацию о разработке см.«Практика разработки FFmpeg: от нулевых основ к короткому онлайн-видео»книга。