/******************************************************************************
*                            recordMyDesktop                                  *
*******************************************************************************
*                                                                             *
*            Copyright (C) 2006,2007 John Varouhakis                          *
*                                                                             *
*                                                                             *
*   This program is free software; you can redistribute it and/or modify      *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation; either version 2 of the License, or         *
*   (at your option) any later version.                                       *
*                                                                             *
*   This program is distributed in the hope that it will be useful,           *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*   GNU General Public License for more details.                              *
*                                                                             *
*   You should have received a copy of the GNU General Public License         *
*   along with this program; if not, write to the Free Software               *
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA  *
*                                                                             *
*                                                                             *
*                                                                             *
*   For further information contact me at johnvarouhakis@gmail.com            *
******************************************************************************/


#include <recordmydesktop.h>

int IncrementalNaming(char **name){
    struct stat buff;
    char *base_name__;
    int i=0;
    base_name__=malloc(strlen(*name)+1);
    strcpy(base_name__,*name);

    //this will go on an endless loop if you have 65536?
    //files with the same name
    //or it will crash and die.anyone interested in trying ?
    while (stat(*name,&buff)==0){
        //create new name
        char *tname=malloc(strlen(*name)+10);
        char numbuf[8];

        strcpy(tname,base_name__);
        strcat(tname,".");
        i++;
        I16TOA((i),numbuf)
        strcat(tname,numbuf);
        //save new name

        free(*name);
        *name=malloc(strlen(tname)+1);
        strcpy(*name,tname);
        free(tname);
    }

    free(base_name__);
    return 0;
}

void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready){
    int y1,y2;
    (pdata)->enc_data=enc_data_t;
    srand(time(NULL));
    y1=rand();
    y2=rand();
    y2+=(y1==y2);

    ogg_stream_init(&enc_data_t->m_ogg_ts,y1);
    if(!pdata->args.nosound)
        ogg_stream_init(&enc_data_t->m_ogg_vs,y2);
    if(!pdata->args.overwrite)
        IncrementalNaming(&(pdata)->args.filename);
    enc_data_t->fp=fopen((pdata)->args.filename,"w");
    if(enc_data_t->fp==NULL){
        fprintf(stderr,"Cannot open file %s for writting!\n",
                       (pdata)->args.filename);
        exit(13);
    }
    theora_info_init(&enc_data_t->m_th_inf);
    enc_data_t->m_th_inf.frame_width=(pdata)->brwin.rgeom.width;
    enc_data_t->m_th_inf.frame_height=(pdata)->brwin.rgeom.height;
    enc_data_t->m_th_inf.width=((enc_data_t->m_th_inf.frame_width+15)>>4)<<4;
    enc_data_t->m_th_inf.height=((enc_data_t->m_th_inf.frame_height+15)>>4)<<4;
    enc_data_t->m_th_inf.offset_x=((enc_data_t->m_th_inf.width-
                                     enc_data_t->m_th_inf.frame_width)/2)&~1;
    enc_data_t->m_th_inf.offset_y=((enc_data_t->m_th_inf.height-
                                     enc_data_t->m_th_inf.frame_height)/2)&~1;
    enc_data_t->m_th_inf.fps_numerator=((pdata)->args.fps*100.0);
    enc_data_t->m_th_inf.fps_denominator=100;
    enc_data_t->m_th_inf.aspect_numerator=1;//(pdata)->brwin.rgeom.width;
    enc_data_t->m_th_inf.aspect_denominator=1;//(pdata)->brwin.rgeom.height;
    enc_data_t->m_th_inf.colorspace=OC_CS_UNSPECIFIED;
    enc_data_t->m_th_inf.pixelformat=OC_PF_420;
    enc_data_t->m_th_inf.target_bitrate=(pdata)->args.v_bitrate;
    enc_data_t->m_th_inf.quality=(pdata)->args.v_quality;
    enc_data_t->m_th_inf.dropframes_p=0;
    enc_data_t->m_th_inf.quick_p=1;
    enc_data_t->m_th_inf.keyframe_auto_p=1;
    enc_data_t->m_th_inf.keyframe_frequency=64;
    enc_data_t->m_th_inf.keyframe_frequency_force=64;
    enc_data_t->m_th_inf.keyframe_data_target_bitrate=
    enc_data_t->m_th_inf.quality*1.5;

    enc_data_t->m_th_inf.keyframe_auto_threshold=80;
    enc_data_t->m_th_inf.keyframe_mindistance=8;
    enc_data_t->m_th_inf.noise_sensitivity=1;
    enc_data_t->m_th_inf.sharpness=2;

    theora_encode_init(&enc_data_t->m_th_st,&enc_data_t->m_th_inf);



    if(!pdata->args.nosound){
        int ret;
        vorbis_info_init(&enc_data_t->m_vo_inf);
        ret = vorbis_encode_init_vbr(&enc_data_t->m_vo_inf,
                                     pdata->args.channels,
                                     pdata->args.frequency,
                                     (float)pdata->args.s_quality*0.1);
        if(ret){
            fprintf(stderr,"Error while setting up vorbis stream quality!\n");
            exit(2);
        }
        vorbis_comment_init(&enc_data_t->m_vo_cmmnt);
        vorbis_analysis_init(&enc_data_t->m_vo_dsp,&enc_data_t->m_vo_inf);
        vorbis_block_init(&enc_data_t->m_vo_dsp,&enc_data_t->m_vo_block);
    }


    theora_encode_header(&enc_data_t->m_th_st,&enc_data_t->m_ogg_pckt1);
    ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1);
    if(ogg_stream_pageout(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pg)!=1){
        fprintf(stderr,"Internal Ogg library error.\n");
        exit(2);
    }
    fwrite(enc_data_t->m_ogg_pg.header,1,
           enc_data_t->m_ogg_pg.header_len,
           enc_data_t->fp);
    fwrite(enc_data_t->m_ogg_pg.body,1,
           enc_data_t->m_ogg_pg.body_len,
           enc_data_t->fp);

    theora_comment_init(&enc_data_t->m_th_cmmnt);
    theora_comment_add_tag(&enc_data_t->m_th_cmmnt,"recordMyDesktop",VERSION);
    theora_encode_comment(&enc_data_t->m_th_cmmnt,&enc_data_t->m_ogg_pckt1);
    ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1);
    theora_encode_tables(&enc_data_t->m_th_st,&enc_data_t->m_ogg_pckt1);
    ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1);


    if(!pdata->args.nosound){
        ogg_packet header;
        ogg_packet header_comm;
        ogg_packet header_code;

        vorbis_analysis_headerout(&enc_data_t->m_vo_dsp,
                                  &enc_data_t->m_vo_cmmnt,
                                  &header,&header_comm,
                                  &header_code);
        ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header);
        if(ogg_stream_pageout(&enc_data_t->m_ogg_vs,&enc_data_t->m_ogg_pg)!=1){
            fprintf(stderr,"Internal Ogg library error.\n");
            exit(2);
        }
        fwrite(enc_data_t->m_ogg_pg.header,1,
               enc_data_t->m_ogg_pg.header_len,
               enc_data_t->fp);
        fwrite(enc_data_t->m_ogg_pg.body,1,
               enc_data_t->m_ogg_pg.body_len,
               enc_data_t->fp);

        ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header_comm);
        ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header_code);
    }



    while(1){
        int result = ogg_stream_flush(&enc_data_t->m_ogg_ts,
                                      &enc_data_t->m_ogg_pg);
        if(result<0){
            fprintf(stderr,"Internal Ogg library error.\n");
            exit(2);
        }
        if(result==0)break;
        fwrite(enc_data_t->m_ogg_pg.header,1,
               enc_data_t->m_ogg_pg.header_len,
               enc_data_t->fp);
        fwrite(enc_data_t->m_ogg_pg.body,1,
               enc_data_t->m_ogg_pg.body_len,
               enc_data_t->fp);
    }

    if(!pdata->args.nosound){
        while(1){
            int result=ogg_stream_flush(&enc_data_t->m_ogg_vs,
                                        &enc_data_t->m_ogg_pg);
            if(result<0){
                fprintf(stderr,"Internal Ogg library error.\n");
                exit(2);
            }
            if(result==0)break;
            fwrite(enc_data_t->m_ogg_pg.header,1,
                   enc_data_t->m_ogg_pg.header_len,
                   enc_data_t->fp);
            fwrite(enc_data_t->m_ogg_pg.body,1,
                   enc_data_t->m_ogg_pg.body_len,
                   enc_data_t->fp);
        }
    }


    if(!buffer_ready){
        enc_data_t->yuv.y=(unsigned char *)malloc(enc_data_t->m_th_inf.height*
                          enc_data_t->m_th_inf.width);
        enc_data_t->yuv.u=(unsigned char *)malloc(enc_data_t->m_th_inf.height*
                          enc_data_t->m_th_inf.width/4);
        enc_data_t->yuv.v=(unsigned char *)malloc(enc_data_t->m_th_inf.height*
                          enc_data_t->m_th_inf.width/4);
        enc_data_t->yuv.y_width=enc_data_t->m_th_inf.width;
        enc_data_t->yuv.y_height=enc_data_t->m_th_inf.height;
        enc_data_t->yuv.y_stride=enc_data_t->m_th_inf.width;

        enc_data_t->yuv.uv_width=enc_data_t->m_th_inf.width/2;
        enc_data_t->yuv.uv_height=enc_data_t->m_th_inf.height/2;
        enc_data_t->yuv.uv_stride=enc_data_t->m_th_inf.width/2;
        enc_data_t->x_offset=enc_data_t->m_th_inf.offset_x;
        enc_data_t->y_offset=enc_data_t->m_th_inf.offset_y;
    }
    theora_info_clear(&enc_data_t->m_th_inf);

}