// File: /workspace/github_cpp_makefile_star2_O2/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
pushq $-0x1
popq %rcx
movl $0x4c4b40, -0x30(%rbp)  # imm = 0x4C4B40
pushq $0xa
popq %rax
movl %eax, -0x38(%rbp)
leaq 0x4de3(%rip), %r12      # 0x7110
movq 0x4c94(%rip), %r13      # 0x6fc8
movl %ecx, -0x2c(%rbp)
movl %ecx, -0x40(%rbp)
movl %ecx, %r14d
movl %r15d, %edi
movq %rbx, %rsi
leaq 0x1cf3(%rip), %rdx      # 0x403d
movq %r12, %rcx
xorl %r8d, %r8d
callq 0x21a0
cmpl $0x77, %eax
jne 0x2368
movq (%r13), %rdi
callq 0x2170
movl %eax, %r14d
jmp 0x233d
leal -0x62(%rax), %ecx
cmpl $0x6, %ecx
ja 0x23b8
leaq 0x1c8d(%rip), %rdx      # 0x4004
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movq (%r13), %rdi
callq 0x2170
movl %eax, -0x30(%rbp)
jmp 0x233d
movq (%r13), %rdi
callq 0x2170
movl %eax, -0x2c(%rbp)
jmp 0x233d
movq (%r13), %rdi
callq 0x2170
movl %eax, -0x40(%rbp)
jmp 0x233d
movq (%r13), %rdi
callq 0x2170
movl %eax, -0x38(%rbp)
jmp 0x233d
cmpl $-0x1, %eax
jne 0x25e6
cmpl $-0x1, %r14d
movl -0x40(%rbp), %r12d
movl -0x2c(%rbp), %r13d
je 0x2616
cmpl $-0x1, %r13d
je 0x2616
cmpl $-0x1, %r12d
je 0x2616
movq 0x4bea(%rip), %rax      # 0x6fd8
movq (%rax), %rdi
movl -0x38(%rbp), %ebx
movl %ebx, (%rsp)
leaq 0x1c76(%rip), %rsi      # 0x4074
movl %r14d, %edx
movl %r13d, %ecx
movl %r12d, %r8d
movl -0x30(%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 0x2678
imull %r13d, %r14d
pushq $0x2
popq %rcx
movl %r14d, %eax
cltd
idivl %ecx
movl %eax, %ebx
addl %r14d, %ebx
movslq %ebx, %r13
testl %r13d, %r13d
pushq $-0x1
popq %rdi
cmovnsq %r13, %rdi
callq 0x2030
movq %rax, %r15
movl %ebx, -0x30(%rbp)
leal (,%r14,4), %eax
testl %r14d, %r14d
pushq $-0x1
popq %rcx
cmovnsl %eax, %ecx
movslq %ecx, %rdi
callq 0x2030
movq %rax, %r12
movslq %r14d, %rax
addq %r15, %rax
movq %rax, -0x40(%rbp)
pushq $0x1
popq %rbx
movl $0x0, -0x2c(%rbp)
movq %r13, -0x38(%rbp)
xorl %r14d, %r14d
movq %r13, %rdx
subq %r14, %rdx
jle 0x24d3
leaq (%r15,%r14), %rsi
xorl %edi, %edi
callq 0x2130
testq %rax, %rax
jle 0x2564
addq %rax, %r14
jmp 0x2491
movq 0x4b1f(%rip), %rax      # 0x6fd8
movq (%rax), %rcx
leaq 0x1c2d(%rip), %rdi      # 0x40f0
pushq $0x18
popq %rsi
pushq $0x1
popq %rdx
callq 0x21e0
callq 0x2150
leaq -0xe8(%rbp), %rdi
movq %r15, %rsi
movq -0x40(%rbp), %rdx
callq 0x28e8
testb %al, %al
je 0x24b2
jmp 0x2512
movl %eax, %r14d
xorl %r13d, %r13d
movq %r14, %rdx
subq %r13, %rdx
jbe 0x2512
leaq (%r12,%r13), %rsi
movl %ebx, %edi
callq 0x2060
addq %rax, %r13
testq %rax, %rax
jns 0x24f2
jmp 0x25b6
leaq -0xe8(%rbp), %rdi
movq %r12, %rsi
callq 0x2b36
testl %eax, %eax
jg 0x24ec
movl -0x2c(%rbp), %r14d
movl %r14d, %eax
xorl %edx, %edx
pushq $0x64
popq %rcx
divl %ecx
testl %edx, %edx
movq -0x38(%rbp), %r13
je 0x2547
incl %r14d
movl %r14d, -0x2c(%rbp)
jmp 0x248e
movq 0x4a8a(%rip), %rax      # 0x6fd8
movq (%rax), %rdi
leaq 0x1bbf(%rip), %rsi      # 0x4117
movl %r14d, %edx
xorl %eax, %eax
callq 0x2120
jmp 0x253b
movq 0x4a6d(%rip), %rbx      # 0x6fd8
movq (%rbx), %rdi
leaq 0x1b4c(%rip), %rsi      # 0x40c1
movq %rax, %rdx
xorl %eax, %eax
callq 0x2120
movq (%rbx), %rdi
leaq 0x1b4b(%rip), %rsi      # 0x40d4
movq %r14, %rdx
movl -0x30(%rbp), %ecx
xorl %eax, %eax
callq 0x2120
leaq -0xe8(%rbp), %rdi
callq 0x2c2e
xorl %eax, %eax
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
pushq $0x8
popq %rdi
callq 0x2090
movq %rax, %rbx
leaq 0x1b41(%rip), %rsi      # 0x4109
movq %rax, %rdi
callq 0x264e
leaq 0x4799(%rip), %rsi      # 0x6d70
movq 0x4a0a(%rip), %rdx      # 0x6fe8
movq %rbx, %rdi
callq 0x21b0
pushq $0x8
popq %rdi
callq 0x2090
movq %rax, %rbx
leaq 0x1a50(%rip), %rsi      # 0x4048
movq %rax, %rdi
callq 0x264e
leaq 0x4769(%rip), %rsi      # 0x6d70
movq 0x49da(%rip), %rdx      # 0x6fe8
movq %rbx, %rdi
callq 0x21b0
pushq $0x8
popq %rdi
callq 0x2090
movq %rax, %rbx
leaq 0x1a30(%rip), %rsi      # 0x4058
jmp 0x25f8
jmp 0x2636
jmp 0x2636
jmp 0x2636
jmp 0x2636
jmp 0x2636
jmp 0x2636
movq %rax, %rbx
leaq -0xe8(%rbp), %rdi
callq 0x2c2e
movq %rbx, %rdi
callq 0x21c0
nop