// File: /workspace/github_cpp_makefile_star2_O3/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movq %rsi, %rbx
movl %edi, %r15d
movl $0xffffffff, -0x40(%rbp) # imm = 0xFFFFFFFF
movl $0x4c4b40, -0x34(%rbp)  # imm = 0x4C4B40
movl $0xa, -0x30(%rbp)
leaq 0x574e(%rip), %r13      # 0x8110
movq 0x55ff(%rip), %r12      # 0x7fc8
movl $0xffffffff, -0x2c(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, %r14d      # imm = 0xFFFFFFFF
movl %r15d, %edi
movq %rbx, %rsi
leaq 0x265a(%rip), %rdx      # 0x503d
movq %r13, %rcx
xorl %r8d, %r8d
callq 0x21a0
cmpl $0x77, %eax
jne 0x2a01
movq (%r12), %rdi
callq 0x2170
movl %eax, %r14d
jmp 0x29d6
leal -0x62(%rax), %ecx
cmpl $0x6, %ecx
ja 0x2a51
leaq 0x25f4(%rip), %rdx      # 0x5004
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movq (%r12), %rdi
callq 0x2170
movl %eax, -0x34(%rbp)
jmp 0x29d6
movq (%r12), %rdi
callq 0x2170
movl %eax, -0x40(%rbp)
jmp 0x29d6
movq (%r12), %rdi
callq 0x2170
movl %eax, -0x30(%rbp)
jmp 0x29d6
movq (%r12), %rdi
callq 0x2170
movl %eax, -0x2c(%rbp)
jmp 0x29d6
cmpl $-0x1, %eax
jne 0x2c9f
cmpl $-0x1, %r14d
movl -0x40(%rbp), %r12d
movl -0x2c(%rbp), %r13d
je 0x2cd1
cmpl $-0x1, %r13d
je 0x2cd1
cmpl $-0x1, %r12d
je 0x2cd1
movq 0x5551(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
movl -0x30(%rbp), %ebx
movl %ebx, (%rsp)
leaq 0x25dd(%rip), %rsi      # 0x5074
movl %r14d, %edx
movl %r13d, %ecx
movl %r12d, %r8d
movl -0x34(%rbp), %r15d
movl %r15d, %r9d
xorl %eax, %eax
callq 0x2120
leaq -0xe8(%rbp), %rdi
movl %r14d, %esi
movl %r13d, %edx
movl %r12d, %ecx
movl %r15d, %r8d
movl %ebx, %r9d
callq 0x2d0a
imull %r13d, %r14d
movl %r14d, %r13d
shrl $0x1f, %r13d
addl %r14d, %r13d
sarl %r13d
addl %r14d, %r13d
movslq %r13d, %rbx
testl %ebx, %ebx
movq $-0x1, %rdi
cmovnsq %rbx, %rdi
callq 0x2030
movq %rax, %r15
leal (,%r14,4), %eax
testl %r14d, %r14d
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmovnsl %eax, %ecx
movslq %ecx, %rdi
callq 0x2030
movq %rax, %r12
movslq %r14d, %rax
addq %r15, %rax
movq %rax, -0x40(%rbp)
movl $0x0, -0x2c(%rbp)
movl %r13d, -0x30(%rbp)
xorl %r14d, %r14d
testl %r13d, %r13d
jle 0x2b52
leaq (%r15,%r14), %rsi
movq %rbx, %rdx
subq %r14, %rdx
xorl %edi, %edi
callq 0x2130
testq %rax, %rax
jle 0x2bd8
addq %rax, %r14
cmpq %rbx, %r14
jl 0x2b30
cmpq %rbx, %r14
jl 0x2c61
leaq -0xe8(%rbp), %rdi
movq %r15, %rsi
movq -0x40(%rbp), %rdx
callq 0x2fc8
testb %al, %al
jne 0x2ba0
callq 0x23d2
jmp 0x2b5b
movl %eax, %r14d
xorl %r13d, %r13d
leaq (%r12,%r13), %rsi
movq %r14, %rdx
subq %r13, %rdx
movl $0x1, %edi
callq 0x2060
testq %rax, %rax
js 0x2c15
addq %rax, %r13
cmpq %r14, %r13
jb 0x2b7f
leaq -0xe8(%rbp), %rdi
movq %r12, %rsi
callq 0x31fc
testl %eax, %eax
jg 0x2b79
movl -0x2c(%rbp), %r14d
imull $0xc28f5c29, %r14d, %eax # imm = 0xC28F5C29
rorl $0x2, %eax
cmpl $0x28f5c28, %eax        # imm = 0x28F5C28
jbe 0x2bf8
incl %r14d
movl %r14d, -0x2c(%rbp)
movl -0x30(%rbp), %r13d
jmp 0x2b28
movq 0x53f9(%rip), %rcx      # 0x7fd8
movq (%rcx), %rdi
leaq 0x24d8(%rip), %rsi      # 0x50c1
movq %rax, %rdx
xorl %eax, %eax
callq 0x2120
jmp 0x2b52
movq 0x53d9(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
leaq 0x250e(%rip), %rsi      # 0x5117
movl %r14d, %edx
xorl %eax, %eax
callq 0x2120
jmp 0x2bc8
movl $0x8, %edi
callq 0x2090
movq %rax, %rbx
leaq 0x516f(%rip), %rax      # 0x7d98
movq %rax, (%rbx)
movq 0x53a5(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
leaq 0x24ea(%rip), %rsi      # 0x5127
leaq 0x24c5(%rip), %rdx      # 0x5109
xorl %eax, %eax
callq 0x2120
leaq 0x511e(%rip), %rsi      # 0x7d70
movq 0x538f(%rip), %rdx      # 0x7fe8
movq %rbx, %rdi
callq 0x21b0
movq 0x5370(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
leaq 0x2462(%rip), %rsi      # 0x50d4
movq %r14, %rdx
movl %r13d, %ecx
xorl %eax, %eax
callq 0x2120
leaq -0xe8(%rbp), %rdi
callq 0x32ce
xorl %eax, %eax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x8, %edi
callq 0x2090
movq %rax, %rbx
leaq 0x2395(%rip), %rsi      # 0x5048
movq %rax, %rdi
callq 0x2210
leaq 0x50ae(%rip), %rsi      # 0x7d70
movq 0x531f(%rip), %rdx      # 0x7fe8
movq %rbx, %rdi
callq 0x21b0
movl $0x8, %edi
callq 0x2090
movq %rax, %rbx
leaq 0x2373(%rip), %rsi      # 0x5058
jmp 0x2cb3
jmp 0x2cf3
jmp 0x2cf3
jmp 0x2cf3
jmp 0x2cf3
jmp 0x2cf3
jmp 0x2cf3
movq %rax, %rbx
leaq -0xe8(%rbp), %rdi
callq 0x32ce
movq %rbx, %rdi
callq 0x21c0