#!/usr/bin/python
import json
import requests
import json
import struct
import requests
import xml.etree.ElementTree as ET

FORMAT_JSON = 'json'
FORMAT_XML = 'xml'
STREAM_HEADER = 0
STREAM_H264 = 1
STREAM_META = 2
STREAM_HEADER_LENGTH = 64
# In sterile scenes the size of the metadata is very small, 256 should suffice.
# If too large, e.g. 1024, old metadata may be visible until the metadata accumulates.
MSG_CHUNK_READ = 256

def process_meta_json(message):
    metadata = json.loads(message)
	# metadata is located under the key 'value0'
    metadata = metadata['value0']
    print('Received JSON metadata')
    print(json.dumps(metadata, indent=4, sort_keys=True))
    with open(f"{metadata['timestamp']}.json", 'w', encoding='utf-8') as f:
        json.dump(metadata, f, indent=4)

def process_meta_xml(message):
    metadata = ET.fromstring(message)
    print('Received XML metadata')
    print(message)
    timestamp = metadata.find('./vca_hdr/timestamp')
    with open(f"{timestamp}.xml", 'w', encoding='utf-8') as f:
        f.write(message[:])


if __name__ == '__main__':
    IP_ADDRESS = '192.168.2.30'
    STREAM_ID = 'first'
    USER_ID = 'root'
    USER_PASSWORD = 'Admin1234'
    OUTPUT_FORMAT = FORMAT_XML # FORMAT_JSON or FORMAT_XML

    s = requests.Session()
    s.auth = requests.auth.HTTPDigestAuth(USER_ID, USER_PASSWORD)
    response = s.get(
        f'http://{IP_ADDRESS}/nvc-cgi/avstream.cgi?streamno={STREAM_ID}&streamreq=meta&format={OUTPUT_FORMAT}',
                    stream=True)

    message_type_to_process = STREAM_HEADER
    message_length_to_read = STREAM_HEADER_LENGTH
    content_reading =  b''

	for content_chunk in response.iter_content(chunk_size=MSG_CHUNK_READ):  # read chunk at a time
		content_reading += content_chunk
		if len(content_reading) < message_length_to_read:
			continue

		# Cut only the length to be processed and pass it on.
		content_to_process = content_reading[:message_length_to_read]
		content_reading = content_reading[message_length_to_read:]

		if message_type_to_process == STREAM_HEADER:
			# check first 25 bytes
			byte_header = b''.join([content_to_process])
			_, _, _, length, _, _, stream_type = struct.unpack('IIIIIIB', byte_header[:25])

			if stream_type == 4:  # 4: H.264
				message_length_to_read = length
				message_type_to_process = STREAM_H264

			elif stream_type == 64: # 64: meta data
				message_length_to_read = length
				message_type_to_process = STREAM_META

		elif message_type_to_process == STREAM_META:
			# The first 32 bytes are skipped because they are structure information for metadata.
			meta = str(content_to_process[32:], 'ascii')
			if OUTPUT_FORMAT == 'xml':
				process_meta_xml(meta)
			if OUTPUT_FORMAT == 'json':
				process_meta_json(meta)
			message_length_to_read = STREAM_HEADER_LENGTH
			message_type_to_process = STREAM_HEADER

		elif message_type_to_process == STREAM_H264:  # Skip H.264 stream data
			print('h.264')
			message_length_to_read = STREAM_HEADER_LENGTH
			message_type_to_process = STREAM_HEADER
    