// File: /workspace/github_cpp_makefile_star2_O1/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 $0xd8, %rsp
movq %rsi, %rbx
movl %edi, %r14d
movl $0xffffffff, -0x48(%rbp) # imm = 0xFFFFFFFF
movl $0x4c4b40, -0x2c(%rbp)  # imm = 0x4C4B40
movl $0xa, -0x38(%rbp)
leaq 0x574e(%rip), %r13      # 0x8110
movq 0x55ff(%rip), %r12      # 0x7fc8
movl $0xffffffff, -0x40(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, %r15d      # imm = 0xFFFFFFFF
movl %r14d, %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, %r15d
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, -0x2c(%rbp)
jmp 0x29d6
movq (%r12), %rdi
callq 0x2170
movl %eax, -0x48(%rbp)
jmp 0x29d6
movq (%r12), %rdi
callq 0x2170
movl %eax, -0x38(%rbp)
jmp 0x29d6
movq (%r12), %rdi
callq 0x2170
movl %eax, -0x40(%rbp)
jmp 0x29d6
cmpl $-0x1, %eax
jne 0x2cbf
cmpl $-0x1, %r15d
movl -0x48(%rbp), %r12d
movl -0x40(%rbp), %r13d
je 0x2cf1
cmpl $-0x1, %r13d
je 0x2cf1
cmpl $-0x1, %r12d
je 0x2cf1
movq 0x5551(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
movl -0x38(%rbp), %ebx
movl %ebx, (%rsp)
leaq 0x25dd(%rip), %rsi      # 0x5074
movl %r15d, %edx
movl %r13d, %ecx
movl %r12d, %r8d
movl -0x2c(%rbp), %r14d
movl %r14d, %r9d
xorl %eax, %eax
callq 0x2120
leaq -0xf8(%rbp), %rdi
movl %r15d, %esi
movl %r13d, %edx
movl %r12d, %ecx
movl %r14d, %r8d
movl %ebx, %r9d
callq 0x2d2a
imull %r13d, %r15d
movl %r15d, %eax
shrl $0x1f, %eax
addl %r15d, %eax
sarl %eax
addl %r15d, %eax
movl %eax, -0x4c(%rbp)
movslq %eax, %r14
testl %r14d, %r14d
movq $-0x1, %rdi
cmovnsq %r14, %rdi
callq 0x2030
movq %rax, %r13
leal (,%r15,4), %eax
testl %r15d, %r15d
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmovnsl %eax, %ecx
movslq %ecx, %rdi
callq 0x2030
movq %rax, %r12
movslq %r15d, %rax
addq %r13, %rax
movq %rax, -0x38(%rbp)
movl $0x0, -0x2c(%rbp)
movq %r14, -0x48(%rbp)
movq %r13, -0x40(%rbp)
xorl %ebx, %ebx
movq %r14, %rdx
subq %rbx, %rdx
jle 0x2b72
leaq (%rbx,%r13), %rsi
xorl %edi, %edi
callq 0x2130
movq %rax, %r15
testq %rax, %rax
jle 0x2b55
addq %r15, %rbx
testq %r15, %r15
jg 0x2b30
jmp 0x2b72
movq 0x547c(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
leaq 0x255b(%rip), %rsi      # 0x50c1
movq %r15, %rdx
xorl %eax, %eax
callq 0x2120
jmp 0x2b4e
cmpq %r14, %rbx
jl 0x2c16
leaq -0xf8(%rbp), %rdi
movq %r13, %rsi
movq -0x38(%rbp), %rdx
callq 0x2fe8
testb %al, %al
jne 0x2b99
callq 0x23d2
jmp 0x2b7b
leaq -0xf8(%rbp), %rdi
movq %r12, %rsi
callq 0x3222
movl %eax, %r15d
testl %eax, %eax
jle 0x2be7
movl %r15d, %r13d
xorl %r14d, %r14d
leaq (%r12,%r14), %rsi
movq %r13, %rdx
subq %r14, %rdx
movl $0x1, %edi
callq 0x2060
testq %rax, %rax
js 0x2c53
addq %rax, %r14
cmpq %r13, %r14
jb 0x2bb5
testl %r15d, %r15d
movq -0x48(%rbp), %r14
movq -0x40(%rbp), %r13
jg 0x2b99
movl -0x2c(%rbp), %r15d
imull $0xc28f5c29, %r15d, %eax # imm = 0xC28F5C29
addl $0x51eb850, %eax        # imm = 0x51EB850
rorl $0x2, %eax
cmpl $0x28f5c28, %eax        # imm = 0x28F5C28
jbe 0x2c36
incl %r15d
movl %r15d, -0x2c(%rbp)
cmpq %r14, %rbx
jge 0x2b2e
jmp 0x2c9f
movq 0x53bb(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
leaq 0x24ad(%rip), %rsi      # 0x50d4
movq %rbx, %rdx
movl -0x4c(%rbp), %ecx
xorl %eax, %eax
callq 0x2120
jmp 0x2c08
movq 0x539b(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
leaq 0x24d0(%rip), %rsi      # 0x5117
movl %r15d, %edx
xorl %eax, %eax
callq 0x2120
jmp 0x2c01
movl $0x8, %edi
callq 0x2090
movq %rax, %rbx
leaq 0x5131(%rip), %rax      # 0x7d98
movq %rax, (%rbx)
movq 0x5367(%rip), %rax      # 0x7fd8
movq (%rax), %rdi
leaq 0x24ac(%rip), %rsi      # 0x5127
leaq 0x2487(%rip), %rdx      # 0x5109
xorl %eax, %eax
callq 0x2120
leaq 0x50e0(%rip), %rsi      # 0x7d70
movq 0x5351(%rip), %rdx      # 0x7fe8
movq %rbx, %rdi
callq 0x21b0
leaq -0xf8(%rbp), %rdi
callq 0x32f4
xorl %eax, %eax
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x8, %edi
callq 0x2090
movq %rax, %rbx
leaq 0x2375(%rip), %rsi      # 0x5048
movq %rax, %rdi
callq 0x2210
leaq 0x508e(%rip), %rsi      # 0x7d70
movq 0x52ff(%rip), %rdx      # 0x7fe8
movq %rbx, %rdi
callq 0x21b0
movl $0x8, %edi
callq 0x2090
movq %rax, %rbx
leaq 0x2353(%rip), %rsi      # 0x5058
jmp 0x2cd3
jmp 0x2d13
jmp 0x2d13
jmp 0x2d13
jmp 0x2d13
jmp 0x2d13
jmp 0x2d13
movq %rax, %rbx
leaq -0xf8(%rbp), %rdi
callq 0x32f4
movq %rbx, %rdi
callq 0x21c0