#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdint>
using namespace std;
int main(int argc, char **argv) {
	if(argc<3) {
		cout<<"Usage: ./grayvideo_flat 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','v','c','1'), fps, cv::Size(width,height));
	if(!writer.isOpened()) {
		cout<<"Error with the file\n";
		return -1;
	}
	cv::Mat frame;
	while(cap.read(frame)) {
		int rows=frame.rows;
		int cols=frame.cols;
		int channels=3;
		// Allocate continuous 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+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;
	}
	// End of while
	cap.release();
	writer.release();
	cout<<"Video transform success\n";
	return 0;
}
// End of main
