Спецификация MJPEG через HTTP

Я пытался создать инструмент для захвата кадров из потока mjpeg, который передается по http. Я не нашел никакой спецификации, поэтому посмотрел, что написано в википедии здесь:

В ответ на запрос GET для файла или потока MJPEG сервер передает последовательность кадров JPEG через HTTP. Специальный тип содержимого mime-типа multipart/x-mixed-replace;boundary=<boundary-name> сообщает клиенту, что он должен ожидать несколько частей (фреймов) в качестве ответа, разделенных <boundary-name>. Это граничное имя явно раскрывается в самом объявлении MIME-типа.

Но на практике это кажется не очень точным. Скинул несколько потоков, чтобы узнать, как они себя ведут. Большинство потоков имеют следующий формат (где CRLF - перевод строки возврата каретки, а частичный заголовок - это некоторые поля заголовка без строки состояния):

Status line (e.g. HTTP/1.0 200 OK) CRLF
Header fields (e.g. Cache-Control: no-cache) CRLF
Content-Type header field (e.g. Content-Type: multipart/x-mixed-replace; boundary=--myboundary) CRLF
CRLF (Denotes that the header is over)
Boundary (Denotes that the first frame is over) CRLF
Partial header fields (mostly: Content-type: image/jpeg) CRLF
CRLF (Denotes that this "partial header" is over)
Actual frame data CRLF
(Sometimes here is an optional CRLF)
Boundary
Starting again at partial header (line 6)

Первый кадр никогда не содержал реальных данных изображения. Все проанализированные потоки имели заголовок Content-Type с типом multipart/x-mixed-replace.

Но некоторые потоки здесь ошибаются:

Два Сервера заявили boundary="MOBOTIX_Fast_Serverpush", но затем использовали --MOBOTIX_Fast_Serverpush в качестве разделителя кадров.

Это меня немного раздражало, поэтому я подумал о другом подходе к получению кадров.

Поскольку каждый JPEG начинается с 0xFF 0xD8 в качестве маркера начала изображения и заканчивается 0xFF 0xD9, я мог бы просто начать их искать. Это кажется очень грязным подходом, и мне он не очень нравится, но он может быть самым надежным.

Прежде чем я начну реализовывать это, есть ли какие-то моменты, которые я упустил из-за MJPEG через HTTP? Есть ли реальная спецификация передачи MJPEG через HTTP? Каковы предостережения, когда вы просто наблюдаете за маркерами начала и конца JPEG вместо использования границы для разделения кадров?


person Eric    schedule 09.12.2017    source источник


Ответы (1)


На практике это кажется не очень точным.

На практике это очень точно. Вы просто неправильно с этим справляетесь.

Первый кадр никогда не содержал реальных данных изображения.

Да. Существует всегда начальная граница перед первым объектом MIME (поскольку MIME может содержать данные пролога перед первым объектом). Вы думаете, что границы MIME существуют только после каждого объекта MIME, но это просто неправда.

Я предлагаю вам прочитать спецификацию MIME, особенно RFC 2045 и RFC 2046. MIME отлично работает в этой ситуации, вы просто неправильно интерпретируете результаты.

Фактические данные кадра CRLF
(Иногда это необязательный CRLF)
Граница

Фактически, этот последний CRLF НЕ является необязательным, он фактически является частью следующей границы, которая следует за данными объекта MIME (см. RFC 2046, раздел 5). Границы MIME должны появляться на отдельных строках, поэтому CRLF искусственно вставляется после данных объекта, что особенно важно для типов данных (например, изображений), которые не завершаются естественным образом их собственным CRLF.

Два Сервера заявили boundary="MOBOTIX_Fast_Serverpush", но затем использовали --MOBOTIX_Fast_Serverpush в качестве разделителя кадров

Вот как предполагается работать с MIME. boundary, указанный в заголовке Content-Type, всегда имеет префикс -- в фактическом потоке сущностей, а конечная граница после последней сущности также имеет суффикс --.

Например:

Content-Type: multipart/x-mixed-replace; boundary="MOBOTIX_Fast_Serverpush"

--MOBOTIX_Fast_Serverpush
Content-Type: image/jpeg

<jpeg bytes>
--MOBOTIX_Fast_Serverpush
Content-Type: image/jpeg

<jpeg bytes>
--MOBOTIX_Fast_Serverpush
... and so on ...
--MOBOTIX_Fast_Serverpush--

Это меня немного раздражало, поэтому я подумал о другом подходе к получению кадров.

То, о чем вы думаете, не сработает и не так надежно, как вы думаете. Вместо этого вам действительно нужно правильно обработать поток MIME.

При обработке multipart/x-mixed-replace вы должны делать следующее:

  1. прочтите и отбросьте тело ответа HTTP, пока не достигнете первой границы MIME, указанной в заголовке ответа Content-Type.
  2. затем прочитайте заголовки и данные объекта MIME, пока не дойдете до следующей подходящей границы MIME.
  3. затем обработать данные объекта по мере необходимости в соответствии с его заголовками (например, отображать image/jpeg объект на экране).
  4. если соединение не было закрыто и последнее считывание границы не является границей завершения, вернитесь к 2, в противном случае прекратите обработку ответа HTTP.
person Remy Lebeau    schedule 21.03.2018