MJPEG (Motion JPEG) Stream Reader - Python

r0ark

Üye
17 May 2018
67
0
MJPEG (Motion JPEG) Nedir?

Motion JPEG, her bir karesi JPEG ile sıkıştırılmış bir video sıkıştırma formatıdır. Multimedya programları için geliştirilmiştir. Şu anda genel olarak dijital kameralar, IP kameralar ve webcamler tarafından kullanılıyor. Bunun yanında, QuickTime Player, PlayStation konsolu ve Safari, Chrome, Mozilla Firefox, Microsoft Edge gibi tarayıcılar tarafından desteklenmektedir.

Bu formatta, her bir kare, "0xff 0xd8" ile başlayıp "0xff 0xd9" ile bitmektedir. Bunu kullanarak her bir kareyi parse edebileceğiz. Aşağıda yapısı bulunuyor.

Kod:
[B][FONT="Courier New"]...(http)
0xff 0xd8      --|
[jpeg data]      |-- frame
0xff 0xd9      --|
...(http)
0xff 0xd8      --|
[jpeg data]      |-- frame
0xff 0xd9      --|
...(http)[/FONT][/B]

Python Uygulaması

GitHub: https://github.com/nulls0/mjpeg-reader
Kod:
[FONT="Courier New"]class MJPEGStream(object):
    def __init__(self, stream_url):
        self.stream_url = stream_url
        self.stream = urllib2.urlopen(self.stream_url)

        self.data = ''
        self.frame = None

        thread = threading.Thread(target=self.start)
        thread.daemon = True
        thread.start()

    def read(self):
        return self.frame

    def start(self):
        while True:
            self.data += self.stream.read(5120)

            start_pos = self.data.find('\xff\xd8')
            end_pos = self.data.find('\xff\xd9')

            if start_pos != -1 and end_pos != -1:
                self.frame = self.data[start_pos:end_pos+2]
                self.data = self.data[end_pos+2:][/FONT]

Gelin, beraber neler olup bittiğini inceleylim. İlk olarak, sınıfı örneklerken, "stream_url" adında bir parametre veriyoruz. Bu URL, yayının yapıldığı yer. Sınıf örneklendikten sonra, yeni bir thread içerisinde sürekli frameleri çekecek olan "start" fonksiyonunu çalıştırıyor.

Kod:
[FONT="Courier New"]    def start(self):
        while True:
            self.data += self.stream.read(5120)

            start_pos = self.data.find('\xff\xd8')
            end_pos = self.data.find('\xff\xd9')

            if start_pos != -1 and end_pos != -1:
                self.frame = self.data[start_pos:end_pos+2]
                self.data = self.data[end_pos+2:][/FONT]

Burada da görüldüğü üzere, döngü her başa dondüğünde yayının yapıldığı yerden 5MB boyutunda data alıyor. Ardından alınan data içerisinde bir karenin başlangıcının ve bitişinin konumlarını bulmaya çalışıyor. Eğer bulursa, aranan değeri "self.frame" değişkenine atıyor ve datadan bu değeri siliyor. Bundan sonra datadan geriye sadece sonraki karenin baştan bir bölümü kalmış oluyor, döngü başa dönüp tekrar data alınca bu sefer yarım kalan kare tamamlanıyor ve datadan siliniyor. Böyle devam ederek her bir kareyi parse etmiş oluyoruz.

Kod:
[FONT="Courier New"]class MJPEGStreamViewer(object):
    def __init__(self, stream):
        self.stream = stream

    def start(self):
        while True:
            frame = self.stream.read()
            if frame == None:
                continue

            frame = numpy.fromstring(frame, dtype=numpy.uint8)
            frame = cv2.resize(cv2.imdecode(frame, 1), (640, 480))
            cv2.imshow('MJPEG Stream Viewer', frame)

            if (cv2.waitKey(5) & 0xFF) == 27:
                sys.exit()[/FONT]

Bu kadar yazmışken, parse edilen frameleri bir videoymuş gibi izleyebilmek için basit bir sınıfta yazdım. Burada, "stream" parametresine bir "MJPEGStream" sınıfı veriyoruz, alınan her frame kullanıcıya bir pencerede gösteriliyor. İnternetten bulduğum bir yayın ile test edelim:

Screenshot_2018-06-21_05-55-42.png

Görüldüğü üzere, uygulamamız gayet güzel çalışıyor.
 
Son düzenleme:
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.