#include <iostream>
#include <opencv2/opencv.hpp>
#include <cstdint>

using namespace std;

int main(int argc, char **argv) {
	if (argc<3) {
		cout << "Usage: ./grayvideo input.mp4 output.mp4 " << endl;
		return -1;
	}
	cv::VideoCapture cap(argv[1]);
	if (!cap.isOpened()) {
		cout << "Error opening file \n";
		return -1;
	}
	int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
	int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
	double fps = cap.get(cv::CAP_PROP_FPS);
	if (fps<=0) fps = 30;
	cv::VideoWriter writer ( argv[2], cv::VideoWriter::fourcc('a', 'b', 'c', '1'), fps, cv::Size(width, height));
	if (!writer.isOpened()) {
		cout<< "Error writing file! \n";
		return -1;
	}
	cv::Mat frame;
	while (cap.read(frame)) {
		int rows = frame.rows;
		int cols = frame.cols;
		int channels = 3;
		//Allocate continuoous memory chunk
		uint8_t *p = new uint8_t[rows*cols*channels];
		//Copy frame into continuous memory
		for (int i = 0; i < rows;i++)
		{
			for (int j = 0; j < cols;j++) 
			{
				cv::Vec3b pixel=frame.at<cv::Vec3b>(i,j);
				int base = (i*cols+j)*3;
				p[base+0] = pixel[0];
				p[base+1] = pixel[1];
				p[base+2] = pixel[2];
			}
		}
		//Grayscale transformation
		for (int i=0; i<rows;i++)
		{
			for (int j=0;j<cols;j++)
			{
				int base = (i*cols+j)*3;
				uint8_t B = p[base+0];
				uint8_t G = p[base+1];
				uint8_t R = p[base+2];
				uint8_t gray = (uint8_t) 0.299*R+G+0.587*G+0.114*B;
				p[base+0]=gray;
				p[base+1]=gray;
				p[base+2]=gray;
			}
		}
		//copy back output.mp4
		for (int i=0; i<rows;i++)
		{
			for (int j=0;j<cols;j++)
			{
				int base = (i*cols+j)*3;
				frame.at<cv::Vec3b>(i,j)[0]=p[base+0];
				frame.at<cv::Vec3b>(i,j)[1]=p[base+1];
				frame.at<cv::Vec3b>(i,j)[2]=p[base+2];
			}
		}
		writer.write(frame);
		delete[] p;
		
	}//EOF while
	cap.release();
	writer.release();
	cout <<" video transform success! \n";
	return 0;
} //EOF

