// File: OtherCrashOverride[P]xu4enc/main.cpp
// Function: main
int main(int argc, char** argv)
{
	int io;


	// options
	int width = -1;
	int height = -1;
	int framerate = -1;
	int bitrate = DEFAULT_BITRATE;
	int gop = 10;


	int c;
	while ((c = getopt_long(argc, argv, "w:h:f:b:g:", longopts, NULL)) != -1)
	{
		switch (c)
		{
			case 'w':
				width = atoi(optarg);
				break;

			case 'h':
				height = atoi(optarg);
				break;

			case 'f':
				framerate = atoi(optarg);
				break;

			case 'b':
				bitrate = atoi(optarg);
				break;

			case 'g':
				gop = atoi(optarg);
				break;

			default:
				throw Exception("Unknown option.");
		}
	}


	if (width == -1 || height == -1 ||
		framerate == -1)
	{
		throw Exception("Required parameter missing.");
	}



	// Initialize the encoder
	fprintf(stderr, "Initialize encoder: width=%d, height=%d, frame_rate=%d, bit_rate=%d, gop=%d\n",
		width, height, framerate, bitrate, gop);

	M2M codec(width, height, framerate, bitrate, gop);
	

	// Start streaming
	int frameCount = 0;

	// TODO: smart pointer
	int bufferSize = width * height;	// Y	
	bufferSize += bufferSize / 2;	// U, V

	unsigned char* input = new unsigned char[bufferSize];

	const int outputBufferSize = width * height * 4;
	char* outputBuffer = new char[outputBufferSize];

	while (true)
	{
		// get buffer
		ssize_t totalRead = 0;
		while (totalRead < bufferSize)
		{
			ssize_t readCount = read(STDIN_FILENO, input + totalRead, bufferSize - totalRead);
			if (readCount <= 0)
			{
				//throw Exception("read failed.");

				// End of stream?
				fprintf(stderr, "read failed. (%d)\n", readCount);

				// TODO: Signal codec and flush
				break;
			}
			else
			{
				totalRead += readCount;
			}
		}

		if (totalRead < bufferSize)
		{
			fprintf(stderr, "read underflow. (%d of %d)\n", totalRead, bufferSize);
			break;
		}


		// Encode the video frames
		while (!codec.EncodeNV12(&input[0], &input[width * height]))
		{
			fprintf(stderr, "codec.EncodeN12 failed.\n");
			std::this_thread::yield();
		}

		while (true)
		{
			int outCnt = codec.GetEncodedData(&outputBuffer[0]);
			if (outCnt <= 0)
			{
				break;
			}

			size_t offset = 0;
			while (offset < outCnt)
			{
				ssize_t writeCount = write(STDOUT_FILENO, &outputBuffer[0] + offset, outCnt - offset);
				if (writeCount < 0)
				{
					throw Exception("write failed.");
				}
				else
				{
					offset += writeCount;
				}
			}
		}

		// Stats
		if ((frameCount % 100) == 0)
		{
			fprintf(stderr, "frameCount=%d.\n", frameCount);
		}

		++frameCount;
	}

	return 0;

#if 0
	// Load the NV12 test data
	int fd = open("default.nv12", O_RDONLY);
	if (fd < 0)
	{
		printf("open failed.\n");
		throw std::exception();
	}
	
	off_t length = lseek(fd, 0, SEEK_END);
	lseek(fd, 0, SEEK_SET);
	
	std::vector<char> data(length);
	ssize_t cnt = read(fd, &data[0], length);
	
	close(fd);
	
	if (cnt != length)
	{
		printf("read failed.\n");
		throw std::exception();
	}
	
	// Create an output file
	mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
	int fdOut = open("default.h264", O_CREAT | O_TRUNC | O_WRONLY, mode);
	if (fdOut < 0)
	{
		printf("open default.h264 failed\n");
		throw std::exception();
	}

	// Initialize the encoder
	M2M codec(1280, 720, 30);

	// Encode the video frames
	const int BUFFER_SIZE = 1280 * 720 * 4;
	char buffer[BUFFER_SIZE];
	int frameCount = 0;
	while (frameCount < 30 * 30)
	{
		printf("loop #%d\n", frameCount);

		if (!codec.EncodeNV12(&data[0], &data[1280 * 720]))
		{
			printf("codec.EncodeN12 failed.\n");
		}
		else
		{
			frameCount++;
		}

		int outCnt;
		do
		{
			outCnt = codec.GetEncodedData(&buffer[0]);
			int offset = 0;
			while (offset < outCnt)
			{
				size_t cnt = write(fdOut, buffer + offset, outCnt - offset);
				if (cnt > 0)
				{
					offset += cnt;
				}
				else
				{
					break;
				}

				printf("write=%d\n", outCnt);
			}
		} while (outCnt > 0);
	}

	close(fdOut);
	
	return 0;
#endif
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x180, %rsp            # imm = 0x180
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0xffffffff, -0x18(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x1c(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x20(%rbp) # imm = 0xFFFFFFFF
movl $0x4c4b40, -0x24(%rbp)  # imm = 0x4C4B40
movl $0xa, -0x28(%rbp)
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
leaq 0x4d43(%rip), %rdx      # 0x708d
leaq 0x8dbf(%rip), %rcx      # 0xb110
xorl %eax, %eax
movl %eax, %r8d
callq 0x21a0
movl %eax, -0x2c(%rbp)
cmpl $-0x1, %eax
je 0x2464
movl -0x2c(%rbp), %eax
addl $-0x62, %eax
movl %eax, %ecx
movq %rcx, -0x138(%rbp)
subl $0x15, %eax
ja 0x2403
movq -0x138(%rbp), %rax
leaq 0x4c77(%rip), %rcx      # 0x7004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x8c2b(%rip), %rax      # 0xafc8
movq (%rax), %rdi
callq 0x2170
movl %eax, -0x18(%rbp)
jmp 0x245f
movq 0x8c14(%rip), %rax      # 0xafc8
movq (%rax), %rdi
callq 0x2170
movl %eax, -0x1c(%rbp)
jmp 0x245f
movq 0x8bfd(%rip), %rax      # 0xafc8
movq (%rax), %rdi
callq 0x2170
movl %eax, -0x20(%rbp)
jmp 0x245f
movq 0x8be6(%rip), %rax      # 0xafc8
movq (%rax), %rdi
callq 0x2170
movl %eax, -0x24(%rbp)
jmp 0x245f
movq 0x8bd2(%rip), %rax      # 0xafc8
movq (%rax), %rdi
callq 0x2170
movl %eax, -0x28(%rbp)
jmp 0x245f
movl $0x8, %edi
callq 0x2090
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x140(%rbp)
leaq 0x4c77(%rip), %rsi      # 0x7098
callq 0x28c0
jmp 0x2428
movq -0x140(%rbp), %rdi
leaq 0x893a(%rip), %rsi      # 0xad70
leaq 0x4e3(%rip), %rdx       # 0x2920
callq 0x21b0
movq -0x140(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
callq 0x20c0
jmp 0x289f
jmp 0x233c
cmpl $-0x1, -0x18(%rbp)
je 0x2476
cmpl $-0x1, -0x1c(%rbp)
je 0x2476
cmpl $-0x1, -0x20(%rbp)
jne 0x24d2
movl $0x8, %edi
callq 0x2090
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x148(%rbp)
leaq 0x4c14(%rip), %rsi      # 0x70a8
callq 0x28c0
jmp 0x249b
movq -0x148(%rbp), %rdi
leaq 0x88c7(%rip), %rsi      # 0xad70
leaq 0x470(%rip), %rdx       # 0x2920
callq 0x21b0
movq -0x148(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
callq 0x20c0
jmp 0x289f
movq 0x8b07(%rip), %rax      # 0xafe0
movq (%rax), %rdi
movl -0x18(%rbp), %edx
movl -0x1c(%rbp), %ecx
movl -0x20(%rbp), %r8d
movl -0x24(%rbp), %r9d
movl -0x28(%rbp), %esi
movq %rsp, %rax
movl %esi, (%rax)
leaq 0x4bcb(%rip), %rsi      # 0x70c4
xorl %eax, %eax
callq 0x2130
movl -0x18(%rbp), %esi
movl -0x1c(%rbp), %edx
movl -0x20(%rbp), %ecx
movl -0x24(%rbp), %r8d
movl -0x28(%rbp), %r9d
leaq -0xe8(%rbp), %rdi
callq 0x2940
movl $0x0, -0xec(%rbp)
movl -0x18(%rbp), %eax
movl -0x1c(%rbp), %ecx
imull %ecx, %eax
movl %eax, -0xf0(%rbp)
movl -0xf0(%rbp), %eax
movl %eax, %edx
shrl $0x1f, %edx
movl %eax, %ecx
addl %edx, %ecx
sarl %ecx
addl %ecx, %eax
movl %eax, -0xf0(%rbp)
movslq -0xf0(%rbp), %rdi
testq %rdi, %rdi
movq $-0x1, %rax
cmovsq %rax, %rdi
callq 0x2030
movq %rax, -0x150(%rbp)
jmp 0x2572
movq -0x150(%rbp), %rax
movq %rax, -0xf8(%rbp)
movl -0x18(%rbp), %eax
movl -0x1c(%rbp), %ecx
imull %ecx, %eax
shll $0x2, %eax
movl %eax, -0xfc(%rbp)
movslq -0xfc(%rbp), %rdi
testq %rdi, %rdi
movq $-0x1, %rax
cmovsq %rax, %rdi
callq 0x2030
movq %rax, -0x158(%rbp)
jmp 0x25b5
movq -0x158(%rbp), %rax
movq %rax, -0x108(%rbp)
jmp 0x25c5
movq $0x0, -0x110(%rbp)
movq -0x110(%rbp), %rax
movslq -0xf0(%rbp), %rcx
cmpq %rcx, %rax
jge 0x2676
movq -0xf8(%rbp), %rsi
movq -0x110(%rbp), %rax
addq %rax, %rsi
movslq -0xf0(%rbp), %rdx
subq %rax, %rdx
xorl %edi, %edi
callq 0x2140
movq %rax, -0x160(%rbp)
jmp 0x2612
movq -0x160(%rbp), %rax
movq %rax, -0x118(%rbp)
cmpq $0x0, -0x118(%rbp)
jg 0x265c
movq 0x89af(%rip), %rax      # 0xafe0
movq (%rax), %rdi
movq -0x118(%rbp), %rdx
leaq 0x4acf(%rip), %rsi      # 0x7111
movb $0x0, %al
callq 0x2130
jmp 0x2676
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
jmp 0x2893
movq -0x118(%rbp), %rax
addq -0x110(%rbp), %rax
movq %rax, -0x110(%rbp)
jmp 0x25d0
movq -0x110(%rbp), %rax
movslq -0xf0(%rbp), %rcx
cmpq %rcx, %rax
jge 0x26b3
movq 0x8950(%rip), %rax      # 0xafe0
movq (%rax), %rdi
movq -0x110(%rbp), %rdx
movl -0xf0(%rbp), %ecx
leaq 0x4a7d(%rip), %rsi      # 0x7124
movb $0x0, %al
callq 0x2130
jmp 0x2874
jmp 0x26b5
movq -0xf8(%rbp), %rsi
movl -0x18(%rbp), %eax
movl -0x1c(%rbp), %ecx
imull %ecx, %eax
cltq
movq %rsi, %rdx
addq %rax, %rdx
leaq -0xe8(%rbp), %rdi
callq 0x2d70
movb %al, -0x161(%rbp)
jmp 0x26e1
movb -0x161(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x26ef
jmp 0x270e
movq 0x88ea(%rip), %rax      # 0xafe0
movq (%rax), %rdi
leaq 0x4a40(%rip), %rsi      # 0x7140
movb $0x0, %al
callq 0x2130
callq 0x3180
jmp 0x26b5
jmp 0x2710
jmp 0x2712
movq -0x108(%rbp), %rsi
leaq -0xe8(%rbp), %rdi
callq 0x31a0
movl %eax, -0x168(%rbp)
jmp 0x272d
movl -0x168(%rbp), %eax
movl %eax, -0x11c(%rbp)
cmpl $0x0, -0x11c(%rbp)
jg 0x2747
jmp 0x282f
movq $0x0, -0x128(%rbp)
movq -0x128(%rbp), %rax
movslq -0x11c(%rbp), %rcx
cmpq %rcx, %rax
jae 0x282a
movq -0x108(%rbp), %rsi
movq -0x128(%rbp), %rax
addq %rax, %rsi
movslq -0x11c(%rbp), %rdx
subq %rax, %rdx
movl $0x1, %edi
callq 0x2060
movq %rax, -0x170(%rbp)
jmp 0x2797
movq -0x170(%rbp), %rax
movq %rax, -0x130(%rbp)
cmpq $0x0, -0x130(%rbp)
jge 0x2810
movl $0x8, %edi
callq 0x2090
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x178(%rbp)
leaq 0x498c(%rip), %rsi      # 0x7159
callq 0x28c0
jmp 0x27d4
movq -0x178(%rbp), %rdi
leaq 0x858e(%rip), %rsi      # 0xad70
leaq 0x137(%rip), %rdx       # 0x2920
callq 0x21b0
jmp 0x28a8
movq -0x178(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
callq 0x20c0
jmp 0x2893
movq -0x130(%rbp), %rax
addq -0x128(%rbp), %rax
movq %rax, -0x128(%rbp)
jmp 0x2752
jmp 0x2710
movl -0xec(%rbp), %eax
movl $0x64, %ecx
cltd
idivl %ecx
cmpl $0x0, %edx
jne 0x2860
movq 0x8797(%rip), %rax      # 0xafe0
movq (%rax), %rdi
movl -0xec(%rbp), %edx
leaq 0x490e(%rip), %rsi      # 0x7167
movb $0x0, %al
callq 0x2130
movl -0xec(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xec(%rbp)
jmp 0x25c3
movl $0x0, -0x4(%rbp)
leaq -0xe8(%rbp), %rdi
callq 0x3360
movl -0x4(%rbp), %eax
addq $0x180, %rsp            # imm = 0x180
popq %rbp
retq
leaq -0xe8(%rbp), %rdi
callq 0x3360
movq -0x38(%rbp), %rdi
callq 0x21c0
nopl (%rax,%rax)