#include<opencv2/opencv.hpp>
#include<iostream>
#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','v','c','1'),fps,cv::Size(width,height));

  if (!writer.isOpened())
  {
  cout<<"Error writing file!" <<endl;
  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 transform
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;
		
		} //EOF while
		
		cap.release();
		writer.release();
		cout << " video transform success! \n";
			return 0;
	} //EOF main
