#!/usr/bin/env python

#import Datagram_pb2

import SocketServer
import sys
import socket
import struct
import threading
import time
import mkvparse

LHOST, LPORT = "localhost", 4444

def ignore_exceptions(command):
    try:
        command()
    except Exception:
        pass

class SimplePublishSubscribe:
    """ Single publisher, maximum one object in queue """
    def __init__(self):
        self.events = (threading.Event(), threading.Event())
        self.object = None
        self.publisher_event_pointer = 0

    def publish(self, object):
        self.object = object
        next_pointer = (self.publisher_event_pointer + 1) % 2
        #print "clearing " + str(next_pointer) + ", setting " + str(self.publisher_event_pointer)
        self.events[next_pointer].clear()
        self.events[self.publisher_event_pointer].set()
        self.publisher_event_pointer = next_pointer
        
    def subscribe(self):
        pointer = 0
        while True:
            #print "waiting for " + str(pointer)
            self.events[pointer].wait()
            pointer = (pointer + 1) % 2
            
            if self.object == StopIteration:
                break
            yield self.object

p = SimplePublishSubscribe()
p.publish(StopIteration)


class MyTCPHandler(SocketServer.BaseRequestHandler):
       
    def handle(self):
        self.afile = self.request.makefile()
        
        if p.object == StopIteration:
            self.afile.write("HTTP/1.0 404 The camera is currently down\r\n");
            self.afile.write("Server: Special mkv->mjpeg streamer for https://bugzilla.mozilla.org/show_bug.cgi?id=858600\r\n");
            self.afile.write("Content-Type: text/plain\r\n");
            self.afile.write("\r\n");
            self.afile.write("Wait for 20 seconds and retry\n");
            return
        else:
            self.afile.write("HTTP/1.0 200 OK\r\n");
            self.afile.write("Server: Special mkv->mjpeg streamer for https://bugzilla.mozilla.org/show_bug.cgi?id=858600\r\n");
            self.afile.write("Content-Type: multipart/x-mixed-replace; boundary=--MyBoundary\r\n");
            self.afile.write("\r\n");
        
        for frame in p.subscribe():
            self.afile.write(
                ("--MyBoundary\r\n"
                 "Content-Type: image/jpeg\r\n"
                 "Content-Length: %d\r\n"
                 "X-Timestamp: %.06f\r\n\r\n"
                 "%s\r\n") % (len(frame), time.time(), frame))
            self.afile.flush()


class MkvToMjpeg(mkvparse.MatroskaHandler):
    def __init__(self, publisher):
        self.vtn=None # video track number

        self.publisher = publisher
        self.previous_timestamp = None

    def tracks_available(self):
        if self.vtn:
            return
        print("Tracks info:")
        for k in self.tracks:
            t=self.tracks[k]
            print("    %d %s %s"%(k, t['type'], t['CodecID']))
            if t['CodecID'][1] == 'V_MJPEG':
                if not self.vtn:
                    print("        Using track %d as video"%k)
                    self.vtn=k
                else:
                    print("        Multiple mjpeg tracks found. Using the first.")
        print("")

        if not self.vtn:
            print("No V_MJPEG video tracks found.")

    def frame(self, track_id, timestamp, data, more_laced_frames, duration, keyframe, invisible, discardable):
        if track_id != self.vtn:
            return
            
        #print(timestamp)
        if self.previous_timestamp:
            tsdelta = timestamp - self.previous_timestamp
            if tsdelta>0:
                time.sleep(tsdelta)
        self.previous_timestamp = timestamp
        
        self.publisher.publish(data)



def streamer(filename):
    while True:
        with open(filename, "rb") as file:
            try:
                handler = MkvToMjpeg(p)
                mkvparse.mkvparse(file, handler)
            except TypeError:
                pass # thrown my mkvparse
        print("Stopped, camera is offline")
        p.publish(StopIteration)
        time.sleep(20)


if __name__ == "__main__":
    if len(sys.argv) != 3:
        sys.stderr.write("Usage: stream_mjpeg_test.py listen_address:listen_port file.mkv\n")
        sys.exit()
    
    LHOST, LPORT = sys.argv[1].split(":")
    LPORT = int(LPORT)
    
    threading.Thread(target = streamer, args=(sys.argv[2],)).start()
    
    SocketServer.ThreadingTCPServer.allow_reuse_address = True
    server = SocketServer.ThreadingTCPServer((LHOST, LPORT), MyTCPHandler)
    try:
        server.serve_forever()
    except (KeyboardInterrupt, SystemExit):
        sys.exit()
