Преобразование байтов потока java mjpeg в изображение

Я получаю поток mjpeg от WiRC.

Документ WiRC описывает следующее о потоке:

Camera image format      JPEG
Camera image resolution  CIF: 352 × 288

В документации описано следующее:

Спецификация пакета

Протокол использует пакеты UDP для передачи потока MJPEG. Поток MJPEG состоит из независимых кадров JPEG. Кадр JPEG отправляется несколькими пакетами. Размер фрагмента определяется серверным приложением.

Первые 16 байтов пакета являются заголовком. Заголовок пакета имеет четыре поля, содержащие 32-битные слова в сетевом порядке байтов (обратный порядок байтов).

name        offset  width    description
version     0       32 bit   protocol version and flags  
frame num   4       32 bit   bit index of the JPEG frame in the stream
offset      8       32 bit   offset of the packet data in the JPEG frame
length      12      32 bit   number of data bytes in the packet beyond the header

Поле версии

Флаги кодируются в старших 16 битах поля версии, младшие 16 бит содержат номер версии (учитывайте порядок байтов хоста при интерпретации поля версии).

name                  bits     description
reserved flag bits    31..17   these bits shall be ignored
last packet flag      16       if set this is the last packet of a JPEG frame
version information   15..0    Protocol version, expected value is 0x5503

Я использую следующий код для декодирования потока в изображение:

int offset = ((int)(bytes[8]  & 255) << 24) |
             ((int)(bytes[9]  & 255) << 16) |
             ((int)(bytes[10] & 255) <<  8) |
             ((int)(bytes[11] & 255));
int length = ((bytes[12]  & 255) << 24) |
             ((bytes[13]  & 255) << 16) |
             ((bytes[14]  & 255) <<  8) |
             ((bytes[15]  & 255));
long frame = ((bytes[4]  & 255) << 24) |
             ((bytes[5]  & 255) << 16) |
             ((bytes[6]  & 255) <<  8) |
             ((bytes[7]  & 255));

System.out.printf("Version: 0x%02X 0x%02X", bytes[2], bytes[3]);

Boolean last = (bytes[1]   &   1) == 1 ? true : false;

System.out.println(" Offset: "+offset+" Length: "+length);
System.out.println("Lastpacket: "+last + " framenum: "+frame);
System.out.println();

Bitmap bmp=BitmapFactory.decodeByteArray(bytes,32,length);

Однако это продолжает возвращать сообщение о том, что BitmapFactory не удалось

Любые идеи или предложения?


В консоли получаю следующий ответ:

UDP received stuff
Version:  0x5503    Offset:     0    Length: 7584
Lastpacket: true    framenum: 223

Изменить: изменен код и добавлен результат консоли.


person user1903531    schedule 05.06.2013    source источник
comment
Увидел небольшой сбой в начальном размере, было 128, а должно было быть 32. Изменил это, завтра снова проверю.   -  person user1903531    schedule 05.06.2013
comment
Где вы собираете рамы? Мне кажется, вы пытаетесь декодировать только части кадров. Помните, что они фрагментированы. Если будете пересобирать, добавьте этот код.   -  person Fildor    schedule 05.06.2013
comment
Я не занимаюсь повторной сборкой, я ожидал, что какой-то счетчик скажет мне, какой кадр я хочу добавить.   -  person user1903531    schedule 05.06.2013
comment
Итак, что мне нужно сделать, это просто объединить кадры, пока я не получу флаг последнего пакета?   -  person user1903531    schedule 05.06.2013
comment
У вас есть номер кадра в заголовке. Как только он меняется, это другой кадр. И помните: UDP может выйти из строя! Ах да, и флаг... так что используйте номер кадра и смещения для заказа.   -  person Fildor    schedule 05.06.2013
comment
Где находится номер рамы? В спецификации об этом ничего не сказано, и смещение всегда равно 0.   -  person user1903531    schedule 05.06.2013
comment
Неважно, я вижу номер кадра, но смещение всегда равно нулю.   -  person user1903531    schedule 05.06.2013
comment
Увеличивается ли число кадров? Тогда изображение может быть достаточно маленьким для одного пакета. В таком случае ошибка в другом.   -  person Fildor    schedule 05.06.2013
comment
Каждые 4 байта: с прямым порядком байтов или с прямым порядком байтов? Вместо 8,9,10,11 это может быть 11,10,9,8 и т. д. Сравните с правдоподобным/проверяемым значением, таким как версия.   -  person Joop Eggen    schedule 05.06.2013
comment
@JoopEggen в сетевом порядке байтов (с обратным порядком байтов). По крайней мере для заголовка, это в вопросе.   -  person Fildor    schedule 05.06.2013
comment
Отредактированный вопрос, показывающий байты версии, можно ли перевернуть байты изображения?   -  person user1903531    schedule 06.06.2013


Ответы (3)


Изображения JPEG фрагментированы по UDP-пакетам, а UDP-пакеты могут быть не в порядке.

Так что вам придется смотреть на заголовки:

  • Номер кадра: тот же номер - тот же кадр
  • Смещение: заказ внутри рамы
  • Флаг последнего пакета: номер кадра этого пакета является последним в кадре.

Теперь вам нужно решить, как соединить их вместе. Я предполагаю, что смещение будет начинаться с 0 для каждого кадра, поэтому должно быть довольно легко что-то придумать.

Не забудьте создать механизм тайм-аута, так как UDP ненадежен.

Например: если у вас есть кадр x, который еще не завершен, а кадр x+1 уже завершен, просто выбросьте его. Или в конечном итоге у вас будет память, полная неполных изображений :)

----РЕДАКТИРОВАТЬ----

Вы можете рассмотреть возможность использования ByteBuffer. . У него есть очень удобные методы для работы с byteorder и int/long любым преобразованием из байтов.

person Fildor    schedule 05.06.2013
comment
Понятно, я посмотрю на это. Однако, насколько я видел, смещение всегда равно 0. - person user1903531; 05.06.2013
comment
Смотрите мой комментарий выше. Возможно, маленькие изображения помещаются в один пакет. Размер имеет какой-то смысл? И количество кадров увеличивается? - person Fildor; 05.06.2013
comment
Кстати: если это целые числа без знака, вы должны использовать long в Java. - person Fildor; 05.06.2013
comment
Насколько я вижу, каждый кадр содержит последний бит кадра. Счетчики кадров хорошо растут. Версия читается правильно, когда я читаю байты: 2 и 3, так что очевидно, что один переключается. Означает ли это, что байты изображения также переворачиваются? - person user1903531; 06.06.2013
comment
Не означает ли это также изменение длины? Это дает мне размер кадра 2016935936, что мне кажется маловероятным. - person user1903531; 06.06.2013
comment
Чего ждать? Что именно вы имеете в виду под флипом? Все должно быть с обратным порядком байтов. Версия бит 15-0... Так если вы читаете байты 2 и 3 и преобразование правильное, то почему тогда оно перевернуто? - person Fildor; 06.06.2013

Я нашел свой собственный баг. Я строил изображения таким образом:

Bitmap bmp=BitmapFactory.decodeByteArray(bytes, 32, length);

Где это должно было быть:

Bitmap bmp=BitmapFactory.decodeByteArray(bytes, 16, length);

Остальное сделали правильно.

Однако спасибо ребята.

person user1903531    schedule 06.06.2013

Для лучшего использования потока mjpeg вам следует использовать библиотеку libjpeg. или этот демонстрационный проект http://www.anddev.org/resources/file/1484

person mohd irfan    schedule 04.12.2013