Длина в вашем коде фактически равна значению пятого байта. Вы сдвигаете все остальные слагаемые как минимум на 8 бит влево, а затем маскируете все, кроме 8 младших битов. Все эти биты равны нулю из-за предыдущей операции сдвига.
Можно реализовать простой дополнительный тест, если данные кадра начинаются с маркера начала изображения JPEG (FF D8
) и заканчиваются маркером конца изображения (DD D9
).
Следующая функция должна выполнять итерацию по изображениям JPEG, разделенным длиной кадра из пяти символов ascii, например VideoStream.java, который вы портировали на Python:
def iter_frames(filename):
with open(filename, 'rb') as mjpeg_file:
while True:
frame_length_bytes = mjpeg_file.read(5)
if len(frame_length_bytes) != 5:
if frame_length_bytes:
raise ValueError('incomplete length')
else:
break
frame_length = int(frame_length_bytes)
frame = mjpeg_file.read(frame_length)
if len(frame) != frame_length:
raise ValueError('incomplete frame data')
if not (
frame.startswith(b'\xff\xd8') and frame.endswith(b'\xff\xd9')
):
raise ValueError('invalid jpeg')
yield frame
def main():
frames = iter_frames('Movie.mjpeg')
frame = next(frames)
with open('test.jpg', 'wb') as jpeg_file:
jpeg_file.write(frame)
if __name__ == '__main__':
main()
Он проверяет, являются ли как значение счетчика байтов, так и данные JPEG полными, и присутствуют ли начальные и конечные маркеры JPEG.
Гораздо проще, чем вы думали, я думаю. Но есть одна загвоздка: этот формат, скорее всего, придумал автор этого Java-класса.
MJPEG — это просто видеокодек, который представляет собой просто объединенные изображения JPEG. Но он очень редко приходит в этом «сыром» формате, а встроен в формат контейнера с метаинформацией, такой как данные MJPEG, частота кадров, возможно, звук и так далее.
Одним из таких форматов является AVI, как в файле MJPEG avi, который вы сослался в комментарии.
Извлечение кадров из такого файла в отдельные изображения JPEG — это немного больше работы, чем чтение изображений JPEG с префиксом простой информации о длине, а затем объединенных в один файл. Нужно реализовать программу чтения AVI, которая достаточно понимает формат AVI, чтобы получить данные кадра. Затем программа для чтения JPEG, которая достаточно понимает формат JPEG, чтобы читать полный кадр, поскольку они сохраняются подряд без какой-либо информации о длине.
Следующая проблема заключается в том, что не все файлы MJPEG содержат кадры, которые можно использовать как отдельные изображения JPEG. В некоторых отсутствует таблица данных (таблица Хаффмана), необходимая для распаковки данных изображения. В спецификации AVI для кодека MJPEG есть фиксированная таблица. Эта таблица используется программным обеспечением для декодирования и должна быть введена в кадр при сохранении в виде файла JPEG.
И последнее «вещь»: есть видео с чересстрочной разверткой, которые не содержат полных изображений, но два последовательных изображения должны быть объединены в одно. Каждое изображение содержит каждую вторую строку. Ваш предоставленный пример MJPEG avi это такое видео. При извлечении кадров без декодирования, деинтерлейсинга и перекодирования каждое изображение будет вдвое меньше высоты видео.
Чтобы получить лучшее представление о том, как выглядят отдельные изображения, эта командная строка ffmpeg
извлекает данные кадра и вставляет отсутствующую таблицу данных, чтобы получить отдельные изображения JPEG:
ffmpeg -i bowlerhatdancer.sleepytom.SGP.mjpeg.avi \
-c:v copy -bsf:v mjpeg2jpeg frame_%04d.jpg
person
BlackJack
schedule
09.04.2015