
#include <android/log.h>
#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif

#include "clib/stdio.h"
#include "clib/stdlib.h"
#include "clib/stdlib.h"
#include "clib/string.h"
#include "libavcodec/avcodec.h"
#include "libavutil/mathematics.h"
#include "libswscale/swscale.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
#include "libavdevice/avdevice.h"
#include "libavutil/avstring.h"
#include "libavutil/pixdesc.h"
#include "libavutil/eval.h"
#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
#define  LOG_TAG    "FFMPEGSample"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

/* definition of data structures */
typedef struct {
  int            x,y;
  unsigned char *data;
  char          *name;
} PPMImage;
typedef PPMImage *img;

typedef struct {
     unsigned char red,green,blue;
} PPMPixel;

/*
typedef struct {
     unsigned char red,green,blue;
} JPGPixel;


typedef struct {
     int x, y;
     JPGPixel *data;
     char          *name;
} JPGImage;
typedef JPGImage *img;

*/
#define CREATOR "RPFELGUEIRAS"
#define RGB_COMPONENT_COLOR 255

/*
static JPGImage *getJPG(char *filename)
{

char buff[16];
JPGImage *img;
FILE *fp;
int c, rgb_comp_color;
//open PPM file for reading
LOGI("try to open file '%s'\n", filename);
    fp = fopen(filename, "rb");
	if (!fp) {
		 LOGI("Unable to open file '%s'\n", filename);

		 exit(1);
	}
	fclose(fp);
	img = (JPGImage*)malloc(sizeof(JPGImage));
     return img;
}
     /*
	LOGI("Buffer size");
	if (!fgets(buff, sizeof(buff), fp)) {
				  perror(filename);
				  exit(1);
	}


	LOGI("Allocating memory");
	img = (JPGImage*)malloc(sizeof(JPGImage));
	//check for comments
	    c = getc(fp);
	    while (c == '#') {
	    while (getc(fp) != '\n') ;
	         c = getc(fp);
	    }
	   /* LOGI("ungetc(c, fp)");
	    ungetc(c, fp);
	    //read image size information
	    if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
	    	LOGI( "Invalid image size (error loading '%s')\n", filename);
	         exit(1);
	    }
	    LOGI("read image size information");
	    //read rgb component
	    if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
	    	LOGI( "Invalid rgb component (error loading '%s')\n", filename);
	         exit(1);
	    }
	    LOGI("check rgb component depth");
	    //check rgb component depth
	 if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
	    	LOGI("'%s' does not have 8-bits components\n", filename);
	         exit(1);
	    }
	 LOGI("memory allocation for pixel data");
	    while (fgetc(fp) != '\n') ;
	    //memory allocation for pixel data
	    img->data = (JPGPixel*)malloc(img->x * img->y * sizeof(JPGPixel));

	    if (!img) {
	    	LOGI( "Unable to allocate memory\n");
	         exit(1);
	    }
	    LOGI("read pixel data from file");
	 //read pixel data from file
	    if (fread(img->data, 3 * img->x, img->y, fp) != img->y) {
	    	LOGI( "Error loading image '%s'\n", filename);
	         exit(1);
	    }
*/
	//  fclose(fp);
    //  return img;
//}


static PPMImage *getPPM(const char *filename)
{
    LOGI("At getPPM:");
         char buff[16];
         PPMImage *img;
         FILE *fp;
         int c, rgb_comp_color;
         //open PPM file for reading
         fp = fopen(filename, "rb");
         if (!fp) {
              LOGI("Unable to open file '%s'\n", filename);
              exit(1);
         }
           //   fclose(fp);
         //     return img;

         LOGI("Reading Image format");
         //read image format
         if (!fgets(buff, sizeof(buff), fp)) {
              perror(filename);
              exit(1);
         }

    //check the image format
    if (buff[0] != 'P' || buff[1] != '6') {
    	LOGI("Invalid image format (must be 'P6')\n");
         exit(1);
    }

     LOGI("Before Memory location");
    //alloc memory form image
    img = (PPMImage*)malloc(sizeof(PPMImage));
    if (!img) {
    	LOGI("Unable to allocate memory\n");
         exit(1);
    }

    //check for comments
    c = getc(fp);
    while (c == '#') {
    while (getc(fp) != '\n') ;
         c = getc(fp);
    }

    ungetc(c, fp);
    //read image size information
    if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
    	LOGI( "Invalid image size (error loading '%s')\n", filename);
         exit(1);
    }

    //read rgb component
    if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
    	LOGI( "Invalid rgb component (error loading '%s')\n", filename);
         exit(1);
    }

    //check rgb component depth
   if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
    	LOGI("'%s' does not have 8-bits components\n", filename);
         exit(1);
    }

    while (fgetc(fp) != '\n') ;
    //memory allocation for pixel data
    img->data = (PPMPixel*)malloc(img->x * img->y * sizeof(PPMPixel));

    if (!img) {
    	LOGI( "Unable to allocate memory\n");
         exit(1);
    }

    //read pixel data from file
    if (fread(img->data, 3 * img->x, img->y, fp) != img->y) {
    	LOGI( "Error loading image '%s'\n", filename);
         exit(1);
    }

    fclose(fp);
    return img;
}


/*
//load PPM image

static PPMImage *getPPM(const char *filename)
{
    char buff[32];
    PPMImage *result;
    FILE *fp;
    int maxval;

    fp = fopen(filename, "rb");
    LOGI("Sucess fully opend file `%s'\n",filename);
    if (!fp)
    {
LOGI("Unable to open file `%s'\n", filename);
	exit(1);
    }

    if (!fgets(buff, sizeof(buff), fp))
    {
	perror(filename);
	exit(1);
    }

    if (buff[0] == 'P' || buff[1] == '6')
    {
    	LOGI("Buffer value one value '%d'\n",buff[1]);
    	LOGI("Buffer value zero value '%d'\n",buff[0]);
    	LOGI("Invalid image format (must be `P6')\n");
	exit(1);
    }

    result = (PPMImage *) malloc(sizeof(PPMImage));
    if (!result)
    {
	LOGI("Unable to allocate memory\n");
	exit(1);
    }

    if (fscanf(fp, "%d %d", &result->x, &result->y) != 2)
    {
	LOGI( "Error loading image `%s'\n", filename);
	exit(1);
    }

    if (fscanf(fp, "%d", &maxval) != 1)
    {
	LOGI( "Error loading image `%s'\n", filename);
	exit(1);
    }

    while (fgetc(fp) != '\n')
	;

    result->data = (char *) malloc(3 * result->x * result->y);
    if (!result)
    {
	LOGI("Unable to allocate memory\n");
	exit(1);
    }

    if (fread(result->data, 3 * result->x, result->y, fp) != result->y)
    {
	LOGI( "Error loading image `%s'\n", filename);
	exit(1);
    }

    fclose(fp);

    return result;
}
*/
/*
  * Audio encoding example
  */
 static void audio_encode_example(const char *filename)
 {
     AVCodec *codec;
     AVCodecContext *c= NULL;
     int frame_size, i, j, out_size, outbuf_size;
     FILE *f;
     short *samples;
     float t, tincr;
     uint8_t *outbuf;

     printf("Audio encoding\n");

     /* find the MP2 encoder */
     codec = avcodec_find_encoder(CODEC_ID_MP2);

     if (!codec) {
         fprintf(stderr, "codec not found\n");
         exit(1);
     }

     c= avcodec_alloc_context();

     /* put sample parameters */
     c->bit_rate =64000;
     c->sample_rate = 44100;
     c->channels = 2;

     /* open it */
     if (avcodec_open(c, codec) < 0) {
         fprintf(stderr, "could not open codec\n");
         exit(1);
     }

     /* the codec gives us the frame size, in samples */
     frame_size = c->frame_size;
     samples = malloc(frame_size * 2 * c->channels);
     outbuf_size = 10000;
     outbuf = malloc(outbuf_size);

     f = fopen(filename, "wb");
     if (!f) {
         fprintf(stderr, "could not open %s\n", filename);
         exit(1);
     }

     /* encode a single tone sound */
     t = 0;
     tincr = 2 * M_PI * 4.0 / c->sample_rate;
     for(i=0;i<0;i++) {
         for(j=0;j<frame_size;j++) {
        	  samples[2*j] = (int)(sin(t) * 10000);
             samples[2*j+1] = samples[2*j];
             t += tincr;
         }
         /* encode the samples */
         out_size = avcodec_encode_audio(c, outbuf, outbuf_size, samples);
        fwrite(outbuf, 1, out_size, f);
    }
     fclose(f);
    free(outbuf);
    free(samples);
    avcodec_close(c);
    av_free(c);
}

 /*
 * Audio decoding.  */
static void audio_decode_example(const char *outfilename, const char *filename)
 {
	 AVCodec *codec;
     AVCodecContext *c= NULL;
     int out_size, len;
     FILE *f, *outfile;
     uint8_t *outbuf;
     uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
     AVPacket avpkt;
     av_init_packet(&avpkt);
     printf("Audio decoding\n");

     /* find the mpeg audio decoder */
    codec = avcodec_find_decoder(CODEC_ID_MP2);
     if (!codec) {
         fprintf(stderr, "codec not found\n");
         exit(1);
     }

     c= avcodec_alloc_context();

     /* open it */
     if (avcodec_open(c, codec) < 0) {
         fprintf(stderr, "could not open codec\n");
exit(1);
     }

     outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);

     f = fopen(filename, "rb");
     if (!f) {
         fprintf(stderr, "could not open %s\n", filename);
         exit(1);
     }
     outfile = fopen(outfilename, "wb");
     if (!outfile) {
         av_free(c);
         exit(1);
     }

     /* decode until eof */
     avpkt.data = inbuf;
     avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);

     while (avpkt.size > 0) {
         out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
         len = avcodec_decode_audio3(c, (short *)outbuf, &out_size, &avpkt);
         if (len < 0) {
             fprintf(stderr, "Error while decoding\n");
             exit(1);
         }
         if (out_size > 0) {
            /* if a frame has been decoded, output it */
             fwrite(outbuf, 1, out_size, outfile);
         }
         avpkt.size -= len;
         avpkt.data += len;
         if (avpkt.size < AUDIO_REFILL_THRESH) {
             /* Refill the input buffer, to avoid trying to decode
              * incomplete frames. Instead of this, one could also use
             * a parser, or use a proper container format through
              * libavformat. */
            memmove(inbuf, avpkt.data, avpkt.size);
             avpkt.data = inbuf;
             len = fread(avpkt.data + avpkt.size, 1,
                         AUDIO_INBUF_SIZE - avpkt.size, f);
             if (len > 0)
                 avpkt.size += len;
         }
     }
     fclose(outfile);
     fclose(f);
     free(outbuf);
     avcodec_close(c);
     av_free(c);
 }
    int encodeVideo()
{
	 LOGI("encode video called");
     char *flname, *err, *info;
     AVCodec *codec;
     AVCodecContext *c= NULL;
     int i,out_size, size, x, y,z, outbuf_size;
     int frameCount=800;
     FILE *f;
     AVFrame *picture,*yuvFrame;
     uint8_t *outbuf, *picture_buf;
      //JPGImage *img;
     PPMImage *img;
     const char *destfilename = "/sdcard/ppmscreencastone.3gp";
     int             numBytes;
     uint8_t         *buffer;
     LOGI("Video encoding\n");
     // find the H263 video encoder
     codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
    // codec = avcodec_find_encoder(CODEC_ID_H263);
     LOGI("After Codec\n");
     if (!codec) {
         sprintf(err, "codec not found\n");
         LOGI("Codec not found\n");
     }
     LOGI("After Codec\n");
     c= avcodec_alloc_context();
     picture= avcodec_alloc_frame();
     LOGI("picture \n");
     yuvFrame= avcodec_alloc_frame();
     LOGI("yuvFrame\n");
     // get first ppm context. it is because I need width and height values.
    // img = getJPG("/sdcard/saved_images/Image10.jpg");
     img = getPPM("/sdcard/first.ppm");
     if(img==NULL){
    	   LOGI("image get from sdcard faild\n");
     }
     LOGI("image get from sdcard\n");
     c->bit_rate = 400000;
     // resolution must be a multiple of two
     c->width = img->x;
     c->height = img->y;
     free(img);
     // frames per second
     LOGI("frames per second\n");
     c->time_base= (AVRational){1,25};
     c->gop_size = 10; // emit one intra frame every ten frames
     //c->max_b_frames=100;
     c->pix_fmt = PIX_FMT_YUV420P;
     // open it
     if (avcodec_open(c, codec) < 0){
    	 	 LOGI("codec couldn't open");
    return -1;
     }
     //destfilename = (*env)->GetStringUTFChars(env, dst, 0);
     f = fopen(destfilename, "wb");
     LOGI(destfilename);
     if (!f) {
         sprintf(err, "could not open %s", destfilename);
         LOGI(err);
     }
     LOGI("after destination file opening");
     // alloc image and output buffer
     outbuf_size = 1000000;
     outbuf = malloc(outbuf_size);
     size = c->width * c->height;
     picture_buf = malloc(size * 3); // size for RGB
     picture->data[0] = picture_buf;
     picture->data[1] = picture->data[0] + size;
     picture->data[2] = picture->data[1] + size / 4;
     picture->linesize[0] = c->width;
     picture->linesize[1] = c->width / 2;
     picture->linesize[2] = c->width / 2;
     numBytes=avpicture_get_size(PIX_FMT_YUV420P, c->width,
              c->height);
     buffer=malloc(numBytes);
          // Assign appropriate parts of buffer to image planes in FrameYUV
     avpicture_fill((AVPicture *)yuvFrame, buffer, PIX_FMT_YUV420P,
              c->width, c->height);
     // encode the video

    /* int num = 123;

         char buf[25];
         strcpy(buf, "venu");
         LOGI("%s\n", buf);
         char bufone[25];
         sprintf(bufone, "%d", num);
     	// print our string
     	 LOGI("%s\n", buf);
     	 LOGI("%s\n",strcat(buf,bufone));
*/
     LOGI("before for loop");
     for(z=1;z<frameCount;z++) {
    /*	  LOGI("After for loop");
          char lnm[6];
          strcpy(lnm, ".jpg");
          LOGI("%s\n",lnm);
          char fnm[20];
    	  char filename[50];
    	  strcpy(filename, "/sdcard/saved_images/Image");
    	  LOGI("%s\n",filename);
    	  sprintf(fnm, "%d", z);
    	  LOGI("%s\n",fnm);
    	  strcat(filename,fnm);
    	  LOGI("%s\n",filename);
    	  strcat(filename,lnm);
    	  LOGI("At Last point%s\n",filename);
		  // read the ppm file
		*/
	//	 img = getJPG("/sdcard/saved_images/Image10.jpg");

    	   img = getPPM("/sdcard/first.ppm");
    	  LOGI("After get ppm");
		  picture->data[0] = img->data;
		  // convert the rgb frame into yuv frame
		  LOGI("before conversion");
		  rgb2yuv(picture,yuvFrame,c);
		  LOGI("translation completed.");
		  // encode the image
		  LOGI("outsize conversion");
		  out_size = avcodec_encode_video(c, outbuf, outbuf_size, yuvFrame);
		  LOGI("After conversion '%d'",out_size);
		  fprintf(info,"encoding frame %3d (size=%5d)\n", z, out_size);
		  fwrite(outbuf, 1, z, f);
		  LOGI("After fwrite");
		  free(img);
		  LOGI("After free");
          }
    /* int count = 1;
    do{
    	LOGI("With in the do loop...loop",count);
    	//sprintf(flname, "/sdcard/saved_images/Image%d.jpg", count);
    	flname = "/sdcard/saved_images/Image1.jpg";
    	LOGI(flname);
    	 count = count +1;
    	 fflush(stdout);
	     img = getJPG(flname);
		 LOGI("Picture data '%d' is....",img->data);
		 picture->data[0] = img->data;
		 // convert the rgb frame into yuv frame
		// rgb2yuv(picture,yuvFrame,c);
		 LOGI("translation completed.");
		 // encode the image
		 out_size = avcodec_encode_video(c, outbuf, outbuf_size, yuvFrame);
		 LOGI("after out_size value");
		 LOGI("Out size value '%d'",out_size);
		// sprintf(info,"encoding frame %3d (size=%5d)\n", z, out_size);
		 LOGI("Out_buf value '%d'",outbuf);
		 LOGI("encoding frame %3d (size=%5d)\n", z);
		 LOGI("encoding frame %3d (size=%5d)\n", out_size);
		 fwrite(outbuf, 1, out_size, f);
		 LOGI("after fwrite completed.");
		 free(img);
		 LOGI("after free completed.");
		 flname = "/sdcard/saved_images/Image'%d'+1.jpg";
    }while(count<699);*/
     /* get the delayed frames */
    /* for(; out_size; i++) {
         fflush(stdout);
		 LOGI("in get delayed frames for loop.");
         out_size = avcodec_encode_video(c, outbuf, outbuf_size, NULL);
         LOGI("in get delayed frames for loop after out_size.");
      //   printf("write frame %3d (size=%5d)\n", i, out_size);
         LOGI("write frame %3d (size=%5d)\n", i);
         fwrite(outbuf, 1, z, f);
         LOGI("after  fwrite(outbuf, 1, out_size, f) completed.");
      }*/

      /* add sequence end code to have a real mpeg file */
     LOGI("Adding sequance..");
     outbuf[0] = 0x00;
     outbuf[1] = 0x00;
     outbuf[2] = 0x01;
     outbuf[3] = 0xb7;
     fwrite(outbuf, 1, 4, f);
     LOGI("Adding sequance.. After fwrite");
     fclose(f);
     LOGI("close the file");
     free(picture_buf);
     free(outbuf);
     avcodec_close(c);
     av_free(c);
     av_free(picture);
     LOGI("Free the PIC");
     printf("\n");
      }

int rgb2yuv(AVFrame *frameRGB, AVFrame *frameYUV, AVCodecContext *c)
{
	LOGI("rgb2yuv starts.......");
        char *err;
        static struct SwsContext *img_convert_ctx;
        LOGI("conversion starts");
        // Convert the image into YUV format from RGB format
        if(img_convert_ctx == NULL) {
                int w = c->width;
                int h = c->height;
                LOGI("Before img_convert_ctx..");
                img_convert_ctx = sws_getContext(w, h, PIX_FMT_RGB24,w, h, c->pix_fmt, SWS_BICUBIC,NULL, NULL, NULL);
                img_convert_ctx = sws_getContext(c->width, c->height, c->pix_fmt, c->width, c->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
                LOGI("After img_convert_ctx..");
                if(img_convert_ctx == NULL) {
                        sprintf(err, "Cannot initialize the conversion context!\n");
                        LOGI(err);
                        return -1;
                }
        }
        LOGI("Before sws_scale..");
        int ret = sws_scale(img_convert_ctx,(const uint8_t* const*)frameRGB->data, frameRGB->linesize , 0,c->height,frameYUV->data, frameYUV->linesize );
        LOGI("rgb returns....ret value");
	    return  ret;
}
 int Java_com_google_video_AndroidVideoRecordingActivity_record()
 {
	 LOGI("avcodec_init called");
     avcodec_init();
     LOGI("avcodec_register_all called");
     avcodec_register_all();
     LOGI("video_encode_example called");
     encodeVideo();
     return 0;
 }
