//___________________________________
uint8_t  A_SaveAudioNVideo(const char *name)
{
     uint32_t needSmart=0,fl;
     GenericAviSave	*nw=NULL;
     aviInfo info;
     uint8_t ret=0;

     video_body->getVideoInfo(&info);

     printf("\n video process mode : %d",videoProcessMode());
     if (!videoProcessMode())
     {
          if(video_body->isMultiSeg()) needSmart=1;
                  video_body->getFlags(frameStart,&fl);
          if(!(fl&AVI_KEY_FRAME)) needSmart=1;

          if(needSmart) printf("\n probably need smart copy mode\n");
      
          if( !isMpeg4Compatible(  info.fcc)
                && !isMSMpeg4Compatible(info.fcc))
             {
                    printf("\n not encodable, cancelling smart mode\n");
                    needSmart=0;
               }


               int value=video_body->getEnv(ENV_EDITOR_SMART);
               nw=NULL;
               if(needSmart)
               {
                  if(value)
                  {
                     nw=new   GenericAviSaveSmart(3);
                  }
                  else
                  {
                    if(GUI_Question(QT_TR_NOOP("You may need smart copy.\n Enable it ?")))
                    {
                        value=4;
                        if( ! GUI_getIntegerValue(&value, 2, 31, "_Q factor (set 4):"))
                                      return 0;
                        nw=new   GenericAviSaveSmart(value);
                    }
                }
               }
              if(!nw)
                    nw=new   GenericAviSaveCopy;
               
       }
       else
       {

              printf("\n Process mode\n");
              nw=new   GenericAviSaveProcess;
        }
     ret=nw->saveAvi(name);
     delete nw;

return ret;
}
/**
    \fn ADM_codecIdFindByFourcc
    \brief get lav codec if from fourcc (used by muxer)
*/
CodecID ADM_codecIdFindByFourcc(const char *fcc)
{
    uint32_t fid=fourCC::get((uint8_t *)fcc);
    // Special cases
 if (isMSMpeg4Compatible (fid) == 1)
    {
      return CODEC_ID_MSMPEG4V3;
    }
  if (isDVCompatible(fid))//"CDVC"))
    {
      return CODEC_ID_DVVIDEO;
    }
  if (isH264Compatible (fid))
    {
        return CODEC_ID_H264;
    }
  if (isMpeg4Compatible (fid) == 1)
    {
      return CODEC_ID_MPEG4;
    }

    uint32_t nb=sizeof(ffCodec)/sizeof(ffVideoCodec);
    for(int i=0;i<nb;i++)
    {
        if(!strcmp(fcc,ffCodec[i].string)) return ffCodec[i].codecId;
    }
    return CODEC_ID_NONE;
}
uint8_t OpenDMLHeader::computePtsDts(void)
{
    // if it is mpeg4-sp, removed packet bitstream & reindex
    if(isMpeg4Compatible(_videostream.fccHandler))  OpenDMLHeader::unpackPacked(  );
    // Now if we have B frames, it is properly tagged
    // Begin by putting PTS=DTS i.e. no B-frames
    for(int i=0;i<_videostream.dwLength;i++)
    {
       odmlIndex *idx=&( _idx[i]);
       idx->pts=ADM_COMPRESSED_NO_PTS;
       idx->dts=frameToUs(i);
    }
    _idx[0].pts=0;
    return 1;
}
int A_SavePackedVop(const char *name)
{
  aviInfo info;
GenericAviSave	*nw;
int ret;

	video_body->getVideoInfo(&info);
	if( !isMpeg4Compatible(  info.fcc))
	{
          GUI_Error_HIG(QT_TR_NOOP("This cannot have packed VOP"),QT_TR_NOOP( "It is not MPEG-4 video. File will not be saved."));
		return 0;
        }
	//
	nw=new   GenericAviSaveCopyPack();
	ret=nw->saveAvi(name);
	delete nw;
	return ret;
}
uint8_t lavMuxer::open(const char *filename,uint32_t inbitrate, ADM_MUXER_TYPE type, aviInfo *info,uint32_t videoExtraDataSize,
                        uint8_t *videoExtraData, WAVHeader *audioheader,uint32_t audioextraSize,uint8_t *audioextraData)
{
 AVCodecContext *c;
 	_type=type;
	_fps1000=info->fps1000;
	switch(_type)
	{
                case MUXER_TS:
                        fmt=guess_format("mpegts", NULL, NULL);
                        break;
		case MUXER_DVD:
			fmt = guess_format("dvd", NULL, NULL);
			break;
		case MUXER_VCD:
			fmt = guess_format("vcd", NULL, NULL);
			break;
		case MUXER_SVCD:
			fmt = guess_format("svcd", NULL, NULL);
			break;
                case MUXER_MP4:
                        fmt = guess_format("mp4", NULL, NULL);
                        break;
                case MUXER_PSP:
                        fmt = guess_format("psp", NULL, NULL);
                        break;                        
		default:
			fmt=NULL;
	}
	if (!fmt) 
	{
        	printf("Lav:Cannot guess format\n");
		return 0;
	}
	oc = av_alloc_format_context();
	if (!oc) 
	{
       		printf("Lav:Cannot allocate context\n");
		return 0;
	}
	oc->oformat = fmt;
	snprintf(oc->filename,1000,"file://%s",filename);
	// Video
	//________
	
	video_st = av_new_stream(oc, 0);
	if (!video_st) 
	{
		printf("Lav: new stream failed\n");
		return 0;
	}	
	
	c = video_st->codec;
	switch(_type)
	{
                case MUXER_MP4:
                        if(isMpeg4Compatible(info->fcc))
                        {
                                c->codec_id = CODEC_ID_MPEG4;
                                c->has_b_frames=1; // in doubt...
                        }else
                        {
                                if(isH264Compatible(info->fcc))
                                {
                                        c->has_b_frames=1; // in doubt...
                                        c->codec_id = CODEC_ID_H264;
                                        c->codec=new AVCodec;
                                        memset(c->codec,0,sizeof(AVCodec));
                                        c->codec->name=ADM_strdup("H264");
                                }
                                else
                                {
                                         c->codec_id = CODEC_ID_MPEG4; // Default value
                                        printf("Ooops, cant mux that...\n");
                                        printf("Ooops, cant mux that...\n");
                                        printf("Ooops, cant mux that...\n");
                                        //return 0;
                                }
                        }
                        if(videoExtraDataSize)
                        {
                                c->extradata=videoExtraData;
                                c->extradata_size= videoExtraDataSize;
                        }
                        c->rc_buffer_size=8*1024*224;
                        c->rc_max_rate=9500*1000;
                        c->rc_min_rate=0;
                        if(!inbitrate)
                                c->bit_rate=9000*1000;
                        else
                                c->bit_rate=inbitrate;
        
                        break;
                case MUXER_TS:
                        c->codec_id = CODEC_ID_MPEG2VIDEO;
                        c->rc_buffer_size=8*1024*224;
                        c->rc_max_rate=9500*1000;
                        c->rc_min_rate=0;
                        if(!inbitrate)
                                c->bit_rate=9000*1000;
                        else
                                c->bit_rate=inbitrate;
        
                        break;
		case MUXER_DVD:
			c->codec_id = CODEC_ID_MPEG2VIDEO;
			c->rc_buffer_size=8*1024*224;
			c->rc_max_rate=9500*1000;
			c->rc_min_rate=0;
			if(!inbitrate)
				c->bit_rate=9000*1000;
			else
				c->bit_rate=inbitrate;
	
			break;
		case MUXER_VCD:
			c->codec_id = CODEC_ID_MPEG1VIDEO;

			c->rc_buffer_size=8*1024*40;
			c->rc_max_rate=1152*1000;
			c->rc_min_rate=1152*1000;
			
			c->bit_rate=1152*1000;
			

			break;
		case MUXER_SVCD:
			c->codec_id = CODEC_ID_MPEG2VIDEO;

			c->rc_buffer_size=8*1024*112;
			c->rc_max_rate=2500*1000;
			c->rc_min_rate=0*1000;
			if(!inbitrate)
				c->bit_rate=2040*1000;
			else
				c->bit_rate=inbitrate;

			break;
		default:
			ADM_assert(0);
	}
	
	c->codec_type = CODEC_TYPE_VIDEO;
	c->flags=CODEC_FLAG_QSCALE;   
	c->width = info->width;  
	c->height = info->height; 
	
    	switch(_fps1000)
	{
		case 25000:
			 c->time_base= (AVRational){1001,25025};
			//c->frame_rate = 25025;  
			//c->frame_rate_base = 1001;	
			break;
		case 23976:
/*
			c->frame_rate = 24000;  
			c->frame_rate_base = 1001;	
			break;
*/
                        if(_type==MUXER_MP4)
                        {
                                 c->time_base= (AVRational){1001,24000};
                                break;
                        }
		case  29970:
			 c->time_base= (AVRational){1001,30000};
			//c->frame_rate = 30000;  
			//c->frame_rate_base = 1001;	
			break;
		default:
                        if(_type==MUXER_MP4)
                        {
                                c->time_base= (AVRational){1000,_fps1000};
                                break;
                        }
                        else
                        {
                          GUI_Error_HIG(_("Incompatible frame rate"), NULL);
                            return 0;
                        }
	}

			
	c->gop_size=15;
	c->max_b_frames=2;
	c->has_b_frames=1;

	
	// Audio
	//________
        if(audioheader)
        {
	audio_st = av_new_stream(oc, 1);
	if (!audio_st) 
	{
		printf("Lav: new stream failed\n");
		return 0;
	}

		
	c = audio_st->codec;
        c->frame_size=1024; //For AAC mainly, sample per frame
        switch(audioheader->encoding)
        {
                case WAV_AC3: c->codec_id = CODEC_ID_AC3;break;
                case WAV_MP2: c->codec_id = CODEC_ID_MP2;break;
                case WAV_MP3:
#warning FIXME : Probe deeper
                            c->frame_size=1152;
                            c->codec_id = CODEC_ID_MP3;
                            break;
                case WAV_PCM: 
                                // One chunk is 10 ms (1/100 of fq)
                                c->frame_size=4;
                                c->codec_id = CODEC_ID_PCM_S16LE;break;
                case WAV_AAC: 
                                c->extradata=audioextraData;
                                c->extradata_size= audioextraSize;
                                c->codec_id = CODEC_ID_AAC;
                                break;
                default:
                        printf("Cant mux that ! audio\n"); 
                        printf("Cant mux that ! audio\n");
                        c->codec_id = CODEC_ID_MP2;
                        return 0;
                        break;
        }
	c->codec_type = CODEC_TYPE_AUDIO;
	
	c->bit_rate = audioheader->byterate*8;
        c->rc_buffer_size=(c->bit_rate/(2*8)); // 500 ms worth
	_audioFq=c->sample_rate = audioheader->frequency;
	c->channels = audioheader->channels;
        _audioByterate=audioheader->byterate;
        }
        // /audio
	
	
//----------------------
	switch(_type)
	{
                case MUXER_MP4:
                        oc->mux_rate=10080*1000; // Needed ?
                        break;

                case MUXER_TS:
                        oc->mux_rate=10080*1000;
                        break;
		case MUXER_DVD:
			oc->packet_size=2048;
			oc->mux_rate=10080*1000;
			break;
		case MUXER_VCD:
			oc->packet_size=2324;
			oc->mux_rate=2352 * 75 * 8;
			
			break;
		case MUXER_SVCD:
			
			oc->packet_size=2324;
			oc->mux_rate=2*2352 * 75 * 8; // ?
			
			break;
		default:
			ADM_assert(0);
	}
	oc->preload=AV_TIME_BASE/10; // 100 ms preloading
	oc->max_delay=200*1000; // 500 ms
	
	if (av_set_parameters(oc, NULL) < 0) 
	{
		printf("Lav: set param failed \n");
		return 0;
	}
	 if (url_fopen(&(oc->pb), filename, URL_WRONLY) < 0) 
	 {
	 	printf("Lav: Failed to open file :%s\n",filename);
		return 0;
        }

	av_write_header(oc);
	dump_format(oc, 0, filename, 1);


	printf("lavformat mpeg muxer initialized\n");
	
	_running=1;

	one=(1000*1000*1000)/_fps1000; 
	_curDTS=one;

	return 1;
}
 decoders *getDecoder(uint32_t fcc,uint32_t w, uint32_t h,uint32_t extraLen,uint8_t *extraData)
 {
				
			if(isMSMpeg4Compatible(fcc)==1)
			{
				// For div3, no problem we take ffmpeg

							return(decoders *)( new decoderFFDiv3(w,h));
			}
			
#ifdef USE_FFMPEG	  
    if(fourCC::check(fcc,(uint8_t *)"dvsd")
      || fourCC::check(fcc,(uint8_t *)"DVDS")
      || fourCC::check(fcc,(uint8_t *)"CDVC")
       )
          {
				
			  				     	return(decoders *)( new decoderFFDV(w,h,extraLen,extraData));
			 }
#endif	
#ifdef USE_FFMPEG	  
    if(fourCC::check(fcc,(uint8_t *)"MP42"))
          {
				
			  				     	return(decoders *)( new decoderFFMP42(w,h));
			    }
#endif	
#ifdef USE_FFMPEG	  
    if(fourCC::check(fcc,(uint8_t *)"H263"))
          {
				
			  				     	return(decoders *)( new decoderFFH263(w,h));
			    }
    if(fourCC::check(fcc,(uint8_t *)"HFYU"))
          {

			  				     	return(decoders *)( new decoderFFhuff(w,h,extraLen,extraData));
	   }

    if(fourCC::check(fcc,(uint8_t *)"SVQ3"))
          {

			  				     	return(decoders *)( new decoderFFSVQ3(w,h,extraLen,extraData));
	   }

    if(fourCC::check(fcc,(uint8_t *)"WMV2"))
          {

			  				     	return(decoders *)( new decoderFFWMV2(w,h,extraLen,extraData));
	   }
 	if(fourCC::check(fcc,(uint8_t *)"FFV1"))
          {

			  				     	return(decoders *)( new decoderFFV1(w,h));
	   }
#endif

/*
	Could be either divx5 packed crap or xvid or ffmpeg
	For now we return FFmpeg and later will switch to divx5 if available
		(ugly hack for ugly hack....)
*/

 	if(isMpeg4Compatible(fcc)==1)
    	{
					          	return(decoders *)( new decoderFFMpeg4(w,h));
						  //	return(decoders *)( new decoderXvid(w,h));
						  //	return(decoders *)( new decoderDIVX(w,h));
	}

          if(fourCC::check(fcc,(uint8_t *)"MJPG") || fourCC::check(fcc,(uint8_t *)"mjpa"))
          {
#if  0
 //#ifdef USE_MJPEG
                      			printf("\n using mjpeg codec\n");
			  				     	return(decoders *)( new decoderMjpeg(w,h));
#else
                      			printf("\n using FF mjpeg codec\n");
			  				     	return(decoders *)( new decoderFFMJPEG(w,h));
#endif

           }
          if(fourCC::check(fcc,(uint8_t *)"YV12"))
          {
            			printf("\n using null codec\n");
			       	return(decoders *)( new decoderNull(w,h));
           }
	if(fourCC::check(fcc,(uint8_t *)"UYVY"))
          {
            			printf("\n using uyvy codec\n");
			       	return(decoders *)( new decoderUYVY(w,h));
           }
	if(fourCC::check(fcc,(uint8_t *)"YUY2"))
          {
            			printf("\n using YUY2 codec\n");
			       	return(decoders *)( new decoderYUY2(w,h));
           }

	   
	   
	if((fcc==0)   ||   fourCC::check(fcc,(uint8_t *)"RGB "))
  			{
            // RGB 16 Codecs
            			printf("\n using RGB codec\n");
			       	return(decoders *)( new decoderRGB16(w,h));

       	}
#ifdef USE_THEORA

         if(fourCC::check(fcc,(uint8_t *)"VP31"))
         {
							printf("\n using Theora codec\n");
			       	return(decoders *)( new decoderTheora(w,h));
	}
#else
   if(fourCC::check(fcc,(uint8_t *)"VP31"))
         {
							printf("\n using VP3 codec\n");
			       	return(decoders *)( new decoderVP3(w,h));
			    }
#endif         
	if(isMpeg12Compatible(fcc))
	{         
		printf("\n using Mpeg1/2 codec (libmpeg2)\n");
	    	return(decoders *)( new decoderMpeg(w,h,extraLen,extraData));
	    //  	return(decoders *)( new decoderFFMpeg12(w,h,extraLen,extraData));
	}

        // default : null decoder
  			printf("\n using invalid codec for \n");
     		fourCC::print(fcc);

       	return(decoders *)( new decoders(w,h));


    	
   }
uint8_t
GenericAviSaveSmart::initEncoder (uint32_t qz)
{
  aviInfo
    info;
  video_body->getVideoInfo (&info);
  assert (0 == encoderReady);
  encoderReady = 1;
  uint8_t ret=0;
  FFcodecSetting myConfig={
	 ME_EPZS,//	ME
	 0, // 		GMC	
	 0,//		_4MV;
	 0,//		_QPEL;	 
	 0,//		_TREILLIS_QUANT
	 2,//		qmin;
	 31,//		qmax;
	 3,//		max_qdiff;
	 0,//		max_b_frames;
	 0, //		mpeg_quant;
	 1,//
	 -2, // 		luma_elim_threshold;
	 1,//
	 -5, // 		chroma_elim_threshold;		 
	 0.05,//		lumi_masking;
	 1,
	 0.01,//		dark_masking; 
	 1,
 	 0.5,// 	qcompress;  /* amount of qscale change between easy & hard scenes (0.0-1.0)*/
    	 0.5,// 	qblur;      /* amount of qscale smoothing over time (0.0-1.0) */

 	} ;


  if(  isMpeg4Compatible(info.fcc) )
  	{
/*	
#ifdef USE_DIVX		 
		 	 _encoder = new divxEncoderCQ (info.width, info.height);
	   
#else			
*/
// 	uint8_t				setConfig(FFcodecSetting *set);	
			ffmpegEncoderCQ *tmp;		
			tmp = new ffmpegEncoderCQ (info.width, info.height,FF_MPEG4);					
			tmp->setConfig(&myConfig);
			printf("\n init qz %ld\n",qz);
	    		ret= tmp->init (qz,25000);
			_encoder=tmp;
/*			
#endif		  		  
*/
		
#warning 25 fps hardcoded

		 }
		 else
		 {
#ifdef USE_FFMPEG			 
			 if(isMSMpeg4Compatible(info.fcc) )
			 {
				 ffmpegEncoderCQ *tmp;
				  tmp = new ffmpegEncoderCQ (info.width, info.height,FF_MSMP4V3);
				  tmp->setConfig(&myConfig);
			    	  ret= tmp->init (qz,25000);
			    	  _encoder=tmp;
				}
				else
					{
				       assert(0);
					}			
			}
#else
			assert(0);
			}			
uint8_t oplug_mp4(const char *name, ADM_OUT_FORMAT type)
{
AVDMGenericVideoStream *_incoming=NULL;
AVDMGenericAudioStream  *audio=NULL;

uint8_t		audioBuffer[48000];
uint8_t         *videoBuffer=NULL;

uint32_t alen;//,flags;
uint32_t size;

uint8_t   ret=0;

uint32_t  sample_got=0,sample;
uint32_t  extraDataSize=0;
uint8_t   *extraData=NULL;
lavMuxer  *muxer=NULL;
aviInfo      info;
uint32_t   width,height;
DIA_encoding *encoding_gui=NULL;
Encoder         *_encode=NULL;
char            *TwoPassLogFile=NULL;
uint32_t total=0;
uint32_t videoExtraDataSize=0;
uint8_t  *videoExtraData=NULL;
uint8_t *dummy,err;
WAVHeader *audioinfo=NULL;
int prefill=0;
uint32_t displayFrame=0;
ADMBitstream    bitstream;
uint32_t        frameWrite=0;
ADM_MUXER_TYPE muxerType=MUXER_MP4;
uint8_t dualPass=0;
uint8_t r=0;
uint32_t skipping=1;
           if(type==ADM_PSP)
               muxerType=MUXER_PSP;
           else
               muxerType=MUXER_MP4;
        // Setup video
        
        if(videoProcessMode())
        {
             _incoming = getLastVideoFilter (frameStart,frameEnd-frameStart);
        }else
        {
             _incoming = getFirstVideoFilter (frameStart,frameEnd-frameStart);
        }

           videoBuffer=new uint8_t[_incoming->getInfo()->width*_incoming->getInfo()->height*3];
                // Set global header encoding, needed for H264
           _encode = getVideoEncoder (_incoming->getInfo()->width,
                        _incoming->getInfo()->height,1);
           total= _incoming->getInfo()->nb_frames;

           encoding_gui=new DIA_encoding(_incoming->getInfo()->fps1000);

           if (!_encode)
                {
                  GUI_Error_HIG (_("Cannot initialize the video stream"), NULL);
                        goto  stopit;
                }

                // init compressor
                encoding_gui->setContainer("MP4");
                encoding_gui->setAudioCodec("None");
                if(!videoProcessMode())
                        encoding_gui->setCodec("Copy");
                else
                        encoding_gui->setCodec(_encode->getDisplayName());
                TwoPassLogFile=new char[strlen(name)+6];
                strcpy(TwoPassLogFile,name);
                strcat(TwoPassLogFile,".stat");
                _encode->setLogFile(TwoPassLogFile,total);

                if (!_encode->configure (_incoming))
                {
                      GUI_Error_HIG (_("Filter init failed"), NULL);
                     goto  stopit;
                };

                dualPass=_encode->isDualPass();
                if(dualPass)
                {
                       
                        if(!prepareDualPass(videoBuffer,TwoPassLogFile,encoding_gui,_encode,total))
                                goto stopit;
                }else
                {
                        encoding_gui->setPhasis ("Encoding");
                }
                
                info.width=_incoming->getInfo()->width;
                info.height=_incoming->getInfo()->height;
                info.nb_frames=_incoming->getInfo()->nb_frames;
                info.fps1000=_incoming->getInfo()->fps1000;
                info.fcc=*(uint32_t *)_encode->getCodecName(); //FIXME
                _encode->hasExtraHeaderData( &videoExtraDataSize,&dummy);
                if(videoExtraDataSize)
                {
                        printf("We have extradata for video in copy mode (%d)\n",videoExtraDataSize);
                        videoExtraData=new uint8_t[videoExtraDataSize];
                        memcpy(videoExtraData,dummy,videoExtraDataSize);
                }
        // _________________Setup video (cont) _______________
        // ___________ Read 1st frame _________________
             
             ADM_assert(_encode);
             bitstream.data=videoBuffer;
             
preFilling:
             bitstream.cleanup(0);
             if(!(err=_encode->encode ( prefill, &bitstream)))//&len, videoBuffer, &flags,&displayFrame))
             {
                        printf("MP4:First frame error\n");
                        GUI_Error_HIG (_("Error while encoding"), NULL);
                        goto  stopit;
              }
              if(!bitstream.len)
              {
                prefill++;
                goto preFilling;
              }
              if(!bitstream.flags & AVI_KEY_FRAME)
              {
                GUI_Error_HIG (_("KeyFrame error"),_( "The beginning frame is not a key frame.\nPlease move the A marker."));
                  goto  stopit; 
              }
           //len=bitstream.len;
           // If needed get VOL header
           if(isMpeg4Compatible(info.fcc) && !videoExtraDataSize && bitstream.len)
           {
                // And put them as extradata for esds atom
                uint32_t voslen=0;
               
                if(extractVolHeader(videoBuffer,bitstream.len,&voslen))
                {
                        if(voslen)
                        {
                                videoExtraDataSize=voslen;
                                videoExtraData=new uint8_t[videoExtraDataSize];
                                memcpy(videoExtraData,videoBuffer,videoExtraDataSize);
                        }
                } else  printf("Oops should be settings data for esds\n");
            }

// ____________Setup audio__________________
          if(currentaudiostream)
          {
                audio=mpt_getAudioStream();
                if(!audio)
                {
                        GUI_Error_HIG (_("Cannot initialize the audio stream"), NULL);
                        goto  stopit;
                }
          } 
          if(audio)
          {
                audioinfo=audio->getInfo();
                audio->extraData(&extraDataSize,&extraData);
                if(audioProcessMode())
                        encoding_gui->setAudioCodec(getStrFromAudioCodec(audio->getInfo()->encoding));
                else
                         encoding_gui->setAudioCodec("Copy");

           }else
           {
                encoding_gui->setAudioCodec("None");
           }
// ____________Setup Muxer _____________________
           muxer= new lavMuxer;
           
           if(!muxer->open(
                name,
                2000000, // Muxrate
                MUXER_MP4,
                &info,videoExtraDataSize,videoExtraData,
                audioinfo,extraDataSize,extraData))
                         goto stopit;
           //_____________ Loop _____________________
          
          encoding_gui->setContainer("MP4");
          if(audio)
                encoding_gui->setAudioCodec(getStrFromAudioCodec(audio->getInfo()->encoding));
          if(!videoProcessMode())
                encoding_gui->setCodec("Copy");
          else
                encoding_gui->setCodec(_encode->getDisplayName());
           //
          if(bitstream.len)
          {
            muxer->writeVideoPacket( &bitstream);
            frameWrite++;
          }

           

           for(int frame=1;frame<total;frame++)
           {
                while(muxer->needAudio())
               {
                     if(!audio->getPacket(audioBuffer,&alen,&sample)) break;
                     if(alen)
                     {
                        muxer->writeAudioPacket(alen,audioBuffer,sample_got);
                        encoding_gui->feedAudioFrame(alen);
                        sample_got+=sample;
                     }
               }
               ADM_assert(_encode);
               bitstream.cleanup(frameWrite);
               if(!prefill || frame+prefill<total) 
               {
                  r=_encode->encode ( prefill+frame, &bitstream);
               }
                else
                {
                    r=_encode->encode ( total-1, &bitstream);
                }
               if(!r)
               {
                        printf("MP4:Frame %u error\n",frame);
                        GUI_Error_HIG (_("Error while encoding"), NULL);
                        goto  stopit;
                }
                if(!bitstream.len && skipping)
                {
                    printf("Frame skipped (xvid ?)\n");
                    continue;
                }
                skipping=0;
            //    printf("Prefill %u FrameWrite :%u Frame %u PtsFrame :%u\n",prefill,frameWrite,frame,bitstream.ptsFrame);
                frameWrite++;
                muxer->writeVideoPacket( &bitstream);

               encoding_gui->setFrame(frame,total);
               encoding_gui->feedFrame(bitstream.len);
               if(!encoding_gui->isAlive())
                {
                  if(GUI_YesNo(_("Stop Request"), _("Do you want to abort encoding ?")))
                                goto stopit;
                }
               
           }
           ret=1;
           
stopit:
           if(muxer) muxer->close();
           if(encoding_gui) delete encoding_gui;
           if(TwoPassLogFile) delete [] TwoPassLogFile;
           if(videoBuffer) delete [] videoBuffer;
           if(muxer) delete muxer;
           if(_encode) delete _encode;	
           if(videoExtraData) delete [] videoExtraData;
           // Cleanup
           deleteAudioFilter (audio);
           return ret;
}
uint8_t lavMuxer::open(const char *filename,uint32_t inbitrate, ADM_MUXER_TYPE type, aviInfo *info,
              uint32_t videoExtraDataSize, uint8_t *videoExtraData, WAVHeader *audioheader,
              uint32_t audioextraSize,uint8_t *audioextraData)
{
 AVCodecContext *c;
 	_type=type;
	_fps1000=info->fps1000;
	switch(_type)
	{
	case MUXER_TS:
		fmt=guess_format("mpegts", NULL, NULL);
		break;
	case MUXER_DVD:
		fmt = guess_format("dvd", NULL, NULL);
		break;
	case MUXER_VCD:
		fmt = guess_format("vcd", NULL, NULL);
		break;
	case MUXER_SVCD:
		fmt = guess_format("svcd", NULL, NULL);
		break;
	case MUXER_MP4:
		fmt = guess_format("mp4", NULL, NULL);
		break;
	case MUXER_PSP:
		fmt = guess_format("psp", NULL, NULL);
		break;
	case MUXER_FLV:
		fmt = guess_format("flv", NULL, NULL);
		break;          
	case MUXER_MATROSKA:
		fmt = guess_format("matroska", NULL, NULL);
		break;          

	default:
		fmt=NULL;
	}
	if (!fmt) 
	{
        	printf("Lav:Cannot guess format\n");
                ADM_assert(0);
		return 0;
	}
	oc = av_alloc_format_context();
	if (!oc) 
	{
       		printf("Lav:Cannot allocate context\n");
		return 0;
	}
	oc->oformat = fmt;
	snprintf(oc->filename,1000,"file://%s",filename);
	// Video
	//________
	
	video_st = av_new_stream(oc, 0);
	if (!video_st) 
	{
		printf("Lav: new stream failed\n");
		return 0;
	}	
	
	c = video_st->codec;
	switch(_type)
	{
				case MUXER_FLV:
					 c->codec=new AVCodec;
					 memset(c->codec,0,sizeof(AVCodec));
					 if(fourCC::check(info->fcc,(uint8_t *)"FLV1"))
					 {
						 c->codec_id=CODEC_ID_FLV1;
					 	 c->codec->name=ADM_strdup("FLV1");
					 }else
					 {
						 if(fourCC::check(info->fcc,(uint8_t *)"VP6F"))
						 			{
							 		 c->codec_id=CODEC_ID_VP6F;
					 				 c->codec->name=ADM_strdup("VP6F");
						 			}
						 else
							 ADM_assert(0);
					 
					 }
					 
					 break;
                case MUXER_MATROSKA:
                        strcpy(oc->title,"Avidemux");
                        strcpy(oc->author,"Avidemux");
                        c->sample_aspect_ratio.num=1;
                        c->sample_aspect_ratio.den=1;
                        if(isMpeg4Compatible(info->fcc))
                        {
                                c->codec_id = CODEC_ID_MPEG4;
                                c->has_b_frames=1; // in doubt...
                        }else
                        {
                                if(isH264Compatible(info->fcc))
                                {
                                        c->has_b_frames=1; // in doubt...
                                        c->codec_id = CODEC_ID_H264;
                                        c->codec=new AVCodec;
                                        memset(c->codec,0,sizeof(AVCodec));
                                        c->codec->name=ADM_strdup("H264");
                                }
                                else
                                {
                                   if(!ADM_4cc_to_lavcodec((const char *)&(info->fcc),&(c->codec_id)))
                                   {
                                      printf("[lavFormat] Cannot map  this\n");
                                      return 0;
                                   }
                                  
                                }
                        }
                        if(videoExtraDataSize)
                        {
                                c->extradata=videoExtraData;
                                c->extradata_size= videoExtraDataSize;
                        }
                        break;
                case MUXER_MP4:
                case MUXER_PSP:
                {
                        // probably a memeleak here
                        char *foo=ADM_strdup(filename);
                        
                        strcpy(oc->title,ADM_GetFileName(foo));
                        strcpy(oc->author,"Avidemux");
                        c->sample_aspect_ratio.num=1;
                        c->sample_aspect_ratio.den=1;
                        if(isMpeg4Compatible(info->fcc))
                        {
                                c->codec_id = CODEC_ID_MPEG4;
                                c->has_b_frames=1; // in doubt...
                        }else
                        {
                                if(isH264Compatible(info->fcc))
                                {
                                        c->has_b_frames=1; // in doubt...
                                        c->codec_id = CODEC_ID_H264;
                                        c->codec=new AVCodec;
                                        memset(c->codec,0,sizeof(AVCodec));
                                        c->codec->name=ADM_strdup("H264");
                                }
                                else
                                {
                                        if(isDVCompatible(info->fcc))
                                        {
                                          c->codec_id = CODEC_ID_DVVIDEO;
                                        }else
                                        {
                                          if(fourCC::check(info->fcc,(uint8_t *)"H263"))
                                          {
                                                    c->codec_id=CODEC_ID_H263;
                                            }else{
                                                    c->codec_id = CODEC_ID_MPEG4; // Default value
                                                    printf("Ooops, cant mux that...\n");
                                                    printf("Ooops, cant mux that...\n");
                                                    printf("Ooops, cant mux that...\n");
                                                }
                                        }
                                }
                        }
                        if(videoExtraDataSize)
                        {
                                c->extradata=videoExtraData;
                                c->extradata_size= videoExtraDataSize;
                        }
                        if(MUXER_PSP==_type)
                        {
                            c->rc_buffer_size=0; //8*1024*224;
                            c->rc_max_rate=0; //768*1000;
                            c->rc_min_rate=0;
                            c->bit_rate=768*1000;
                        }
                        else
                        {
                            c->rc_buffer_size=8*1024*224;
                            c->rc_max_rate=9500*1000;
                            c->rc_min_rate=0;
                            if(!inbitrate)
                                    c->bit_rate=9000*1000;
                            else
                                    c->bit_rate=inbitrate;
                        }
                }
                        break;
                case MUXER_TS:
                        c->codec_id = CODEC_ID_MPEG2VIDEO;
                        c->rc_buffer_size=8*1024*224;
                        c->rc_max_rate=9500*1000;
                        c->rc_min_rate=0;
                        if(!inbitrate)
                                c->bit_rate=9000*1000;
                        else
                                c->bit_rate=inbitrate;
        
                        break;
		case MUXER_DVD:
			c->codec_id = CODEC_ID_MPEG2VIDEO;
			c->rc_buffer_size=8*1024*224;
			c->rc_max_rate=9500*1000;
			c->rc_min_rate=0;
			if(!inbitrate)
				c->bit_rate=9000*1000;
			else
				c->bit_rate=inbitrate;
	
			break;
		case MUXER_VCD:
			c->codec_id = CODEC_ID_MPEG1VIDEO;

			c->rc_buffer_size=8*1024*40;
			c->rc_max_rate=1152*1000;
			c->rc_min_rate=1152*1000;
			
			c->bit_rate=1152*1000;
			

			break;
		case MUXER_SVCD:
			c->codec_id = CODEC_ID_MPEG2VIDEO;

			c->rc_buffer_size=8*1024*112;
			c->rc_max_rate=2500*1000;
			c->rc_min_rate=0*1000;
			if(!inbitrate)
				c->bit_rate=2040*1000;
			else
				c->bit_rate=inbitrate;

			break;
		default:
			ADM_assert(0);
	}
	
	c->codec_type = CODEC_TYPE_VIDEO;
	c->flags=CODEC_FLAG_QSCALE;   
	c->width = info->width;  
	c->height = info->height; 

       AVRational fps25=(AVRational){1001,25025};
       AVRational fps24=(AVRational){1001,24000};
       AVRational fps30= (AVRational){1001,30000};
       AVRational fpsfree= (AVRational){1000,_fps1000};

        
    	switch(_fps1000)
	{
		case 25000:
                {
			 c->time_base= fps25; 
			 break;
                }
		case 23976:
                        if(_type==MUXER_MP4 || _type==MUXER_PSP || _type==MUXER_FLV || _type==MUXER_MATROSKA)
                        {
                                 c->time_base= fps24; //(AVRational){1001,24000};
                                break;
                        }
		case  29970:
			 c->time_base=fps30;
			break;
		default:
                      {
                            if(_type==MUXER_MP4 || _type==MUXER_PSP || _type==MUXER_FLV || _type==MUXER_MATROSKA)
                            {
                                    c->time_base=fpsfree;// (AVRational){1000,_fps1000};
                                    break;
                            }
                            else
                            {
                                GUI_Error_HIG(QT_TR_NOOP("Incompatible frame rate"), NULL);
                                return 0;
                            }
                            }
                        break;
	}

			
	c->gop_size=15;
	c->max_b_frames=2;
	c->has_b_frames=1;

	
	// Audio
	//________
        if(audioheader)
        {
          audio_st = av_new_stream(oc, 1);
          if (!audio_st) 
          {
                  printf("Lav: new stream failed\n");
                  return 0;
          }
  
                  
          c = audio_st->codec;
          c->frame_size=1024; //For AAC mainly, sample per frame
          printf("[LavFormat] Bitrate %u\n",(audioheader->byterate*8)/1000);
          _audioFq=c->sample_rate = audioheader->frequency;
#if 0
           if(_type== MUXER_PSP && audioheader->encoding==WAV_AAC)
            {
                    _audioFq=c->sample_rate = audioheader->frequency/2;                 //_audioFq*=2; // SBR
             }
#endif
          
          switch(audioheader->encoding)
          {
                  case WAV_AC3: c->codec_id = CODEC_ID_AC3;break;
                  case WAV_MP2: c->codec_id = CODEC_ID_MP2;break;
                  case WAV_MP3:
  #warning FIXME : Probe deeper
                              c->frame_size=1152;
                              c->codec_id = CODEC_ID_MP3;
                              break;
                  case WAV_PCM: 
                                  // One chunk is 10 ms (1/100 of fq)
                                  c->frame_size=4;
                                  c->codec_id = CODEC_ID_PCM_S16LE;break;
                  case WAV_AAC: 
                                  c->extradata=audioextraData;
                                  c->extradata_size= audioextraSize;
                                  c->codec_id = CODEC_ID_AAC;
                                  break;
                  default:
                          if(_type==MUXER_MATROSKA)
                          {
                           if(ADM_WaveTag_to_lavcodec(audioheader->encoding, &(c->codec_id)))
                           {
                             if(audioextraData)
                             {
                                  c->extradata=audioextraData;
                                  c->extradata_size= audioextraSize;
                             }
                             // Put a dummy time increment
                              c->time_base= fps25;
                             break;
                           }
                          }
                            
                          printf("Cant mux that ! audio\n"); 
                          printf("Cant mux that ! audio\n");
                          c->codec_id = CODEC_ID_MP2;
                          return 0;
                          break;
          }
          c->codec_type = CODEC_TYPE_AUDIO;
          
          c->bit_rate = audioheader->byterate*8;
          c->rc_buffer_size=(c->bit_rate/(2*8)); // 500 ms worth
          
          c->channels = audioheader->channels;
          _audioByterate=audioheader->byterate;
          
        }
        // /audio
	
	
//----------------------
	switch(_type)
	{
				case MUXER_FLV:
                case MUXER_PSP:
                case MUXER_MP4:
                case MUXER_MATROSKA:
                        oc->mux_rate=10080*1000; // Needed ?
                        break;

                case MUXER_TS:
                        oc->mux_rate=10080*1000;
                        break;
		case MUXER_DVD:
			oc->packet_size=2048;
			oc->mux_rate=10080*1000;
			break;
		case MUXER_VCD:
			oc->packet_size=2324;
			oc->mux_rate=2352 * 75 * 8;
			
			break;
		case MUXER_SVCD:
			
			oc->packet_size=2324;
			oc->mux_rate=2*2352 * 75 * 8; // ?
			
			break;
		default:
			ADM_assert(0);
	}
	oc->preload=AV_TIME_BASE/10; // 100 ms preloading
	oc->max_delay=200*1000; // 500 ms
	
	if (av_set_parameters(oc, NULL) < 0) 
	{
		printf("Lav: set param failed \n");
		return 0;
	}
	 if (url_fopen(&(oc->pb), filename, URL_WRONLY) < 0) 
	 {
	 	printf("Lav: Failed to open file :%s\n",filename);
		return 0;
        }

	ADM_assert(av_write_header(oc)>=0);
	dump_format(oc, 0, filename, 1);


	printf("lavformat mpeg muxer initialized\n");
	
	_running=1;

	one=(1000*1000*1000)/_fps1000; 
	_curDTS=one;

	return 1;
}
bool muxerMp4v2::open(const char *file, ADM_videoStream *s,uint32_t nbAudioTrack,ADM_audioStream **a)
{

        audioDelay=s->getVideoDelay();
        vStream=s;
        nbAStreams=nbAudioTrack;
        aStreams=a;
        videoBufferSize=vStream->getWidth()*vStream->getHeight()*3;
        videoBuffer[0]=new uint8_t[videoBufferSize];
        videoBuffer[1]=new uint8_t[videoBufferSize];
        scratchBuffer=new uint8_t[videoBufferSize];
        in[0].bufferSize=videoBufferSize;
        in[0].data=videoBuffer[0];
        in[1].bufferSize=videoBufferSize;
        in[1].data=videoBuffer[1];
        targetFileName=string(file);
//------Verify everything is ok : Accept Mp4 & H264 for video, AAC for audio ----
        uint32_t fcc=vStream->getFCC();
        if(!isH264Compatible(fcc) && !isMpeg4Compatible(fcc))
        {
            ADM_error("[mp4v2] Only h264 and mp4 video track!\n");
            return false;
        }
        for(int i=0;i<nbAStreams;i++)
        {
            int encoding=aStreams[i]->getInfo()->encoding;
            switch(encoding)
            {
                case WAV_MP2:case WAV_MP3:case WAV_AAC:case WAV_AC3:
                            continue;
                default:
                    GUI_Error_HIG("Audio","Audio format not supported, only AAC/MP3/AC3");
                    return false;
            }            
        }
//------Verify everything is ok : Accept Mp4 & H264 for video, AAC for audio ----
        
        // Create file
        handle=MP4Create( file,  ADM_MP4_OPTIONS_OPEN);
        if(MP4_INVALID_FILE_HANDLE==handle)
        {
            ADM_error("[mp4v2]Cannot create output file %s\n",file);
            return false;
        }
        MP4LogSetLevel(MP4_LOG_INFO);
        
        if (!(MP4SetTimeScale( handle, 90*1000 ))) // 90 kHz tick
        {
            ADM_error("[mp4v2]Cannot set timescale to us\n");
            return false;
        }
        if(false==initVideo())
        {
            ADM_error("Cannot init video\n");
            return false;
        }
        if(false==initAudio())
        {
            ADM_error("Cannot init audio\n");
            return false;
        }

        return true;
er:
        return false;
}
uint8_t oplug_mp4(const char *name, ADM_OUT_FORMAT type)
{
AVDMGenericVideoStream *_incoming=NULL;
AVDMGenericAudioStream  *audio=NULL;

uint8_t		audioBuffer[48000];
uint8_t         *videoBuffer=NULL;

uint32_t alen;//,flags;
uint32_t size;

uint8_t   ret=0;

uint32_t  sample_got=0,sample;
uint32_t  extraDataSize=0;
uint8_t   *extraData=NULL;
lavMuxer  *muxer=NULL;
aviInfo      info;
uint32_t   width,height;
DIA_encoding *encoding_gui=NULL;
Encoder         *_encode=NULL;
char            *TwoPassLogFile=NULL;
uint32_t total=0;
uint32_t videoExtraDataSize=0;
uint8_t  *videoExtraData=NULL;
uint8_t *dummy,err;
WAVHeader *audioinfo=NULL;
int prefill=0;
uint32_t displayFrame=0;
ADMBitstream    bitstream(0);
uint32_t        frameWrite=0;
ADM_MUXER_TYPE muxerType=MUXER_MP4;
uint8_t dualPass=0;
uint8_t r=0;
uint32_t skipping=1;
pthread_t     audioThread;
audioQueueMT context;
PacketQueue   *pq;//("MP4 audioQ",50,2*1024*1024);
uint32_t    totalAudioSize=0;
uint32_t sent=0;
const char *containerTitle;
           switch(type)
           {
             case ADM_PSP:muxerType=MUXER_PSP;containerTitle="PSP";break;
             case ADM_MP4:muxerType=MUXER_MP4;containerTitle="MP4";break;
             case ADM_MATROSKA:muxerType=MUXER_MATROSKA;containerTitle="MKV";break;
             default:
                ADM_assert(0);
           }
        // Setup video
        
        if(videoProcessMode())
        {
             _incoming = getLastVideoFilter (frameStart,frameEnd-frameStart);
        }else
        {
             _incoming = getFirstVideoFilter (frameStart,frameEnd-frameStart);
        }

           videoBuffer=new uint8_t[_incoming->getInfo()->width*_incoming->getInfo()->height*3];
                // Set global header encoding, needed for H264
           _encode = getVideoEncoder (_incoming->getInfo()->width,
                        _incoming->getInfo()->height,1);
           total= _incoming->getInfo()->nb_frames;

           encoding_gui=new DIA_encoding(_incoming->getInfo()->fps1000);
           bitstream.bufferSize=_incoming->getInfo()->width*_incoming->getInfo()->height*3;
           if (!_encode)
                {
                  GUI_Error_HIG (QT_TR_NOOP("Cannot initialize the video stream"), NULL);
                        goto  stopit;
                }

                // init compressor
               
                  encoding_gui->setContainer(containerTitle);
               
                encoding_gui->setAudioCodec("None");
                if(!videoProcessMode())
                        encoding_gui->setCodec("Copy");
                else
                        encoding_gui->setCodec(_encode->getDisplayName());
                TwoPassLogFile=new char[strlen(name)+6];
                strcpy(TwoPassLogFile,name);
                strcat(TwoPassLogFile,".stat");
                _encode->setLogFile(TwoPassLogFile,total);

                if (!_encode->configure (_incoming))
                {
                      GUI_Error_HIG (QT_TR_NOOP("Filter init failed"), NULL);
                     goto  stopit;
                };

                dualPass=_encode->isDualPass();
                if(dualPass)
                {
                       
                        if(!prepareDualPass(bitstream.bufferSize,videoBuffer,TwoPassLogFile,encoding_gui,_encode,total))
                                goto stopit;
                }else
                {
                        encoding_gui->setPhasis ("Encoding");
                }
                
                info.width=_incoming->getInfo()->width;
                info.height=_incoming->getInfo()->height;
                info.nb_frames=_incoming->getInfo()->nb_frames;
                info.fps1000=_incoming->getInfo()->fps1000;
                info.fcc=*(uint32_t *)_encode->getCodecName(); //FIXME
                _encode->hasExtraHeaderData( &videoExtraDataSize,&dummy);
                if(videoExtraDataSize)
                {
                        printf("We have extradata for video in copy mode (%d)\n",videoExtraDataSize);
                        videoExtraData=new uint8_t[videoExtraDataSize];
                        memcpy(videoExtraData,dummy,videoExtraDataSize);
                }
        // _________________Setup video (cont) _______________
        // ___________ Read 1st frame _________________
             
             ADM_assert(_encode);
             bitstream.data=videoBuffer;
             
preFilling:
             bitstream.cleanup(0);
             if(!(err=_encode->encode ( prefill, &bitstream)))//&len, videoBuffer, &flags,&displayFrame))
             {
                        printf("MP4:First frame error\n");
                        GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL);
                        goto  stopit;
              }
              sent++;
              if(!bitstream.len)
              {
                prefill++;
                goto preFilling;
              }
              printf("Pass 2 prefill : %u\n",prefill);
              if(!bitstream.flags & AVI_KEY_FRAME)
              {
                GUI_Error_HIG (QT_TR_NOOP("KeyFrame error"),QT_TR_NOOP( "The beginning frame is not a key frame.\nPlease move the A marker."));
                  goto  stopit; 
              }
           //len=bitstream.len;
           // If needed get VOL header
           if(isMpeg4Compatible(info.fcc) && !videoExtraDataSize && bitstream.len)
           {
                // And put them as extradata for esds atom
                uint32_t voslen=0;
               
                if(extractVolHeader(videoBuffer,bitstream.len,&voslen))
                {
                        if(voslen)
                        {
                                videoExtraDataSize=voslen;
                                videoExtraData=new uint8_t[videoExtraDataSize];
                                memcpy(videoExtraData,videoBuffer,videoExtraDataSize);
                        }
                } else  printf("Oops should be settings data for esds\n");
            }

// ____________Setup audio__________________
          if(currentaudiostream)
          {
                audio=mpt_getAudioStream();
                if(!audio)
                {
                        GUI_Error_HIG (QT_TR_NOOP("Cannot initialize the audio stream"), NULL);
                        goto  stopit;
                }
          } 
          if(audio)
          {
                audioinfo=audio->getInfo();
                audio->extraData(&extraDataSize,&extraData);
                if(audioProcessMode())
                        encoding_gui->setAudioCodec(getStrFromAudioCodec(audio->getInfo()->encoding));
                else
                         encoding_gui->setAudioCodec("Copy");

           }else
           {
                encoding_gui->setAudioCodec("None");
           }
// ____________Setup Muxer _____________________
           muxer= new lavMuxer;
           
           if(!muxer->open(
                name,
                2000000, // Muxrate
                muxerType,
                &info,videoExtraDataSize,videoExtraData,
                audioinfo,extraDataSize,extraData))
                         goto stopit;
//_____________ Loop _____________________
          
          encoding_gui->setContainer(containerTitle);
         
          if(!videoProcessMode())
                encoding_gui->setCodec("Copy");
          else
                encoding_gui->setCodec(_encode->getDisplayName());
           //
          UI_purge();
          if(bitstream.len)
          {
            muxer->writeVideoPacket( &bitstream);
            frameWrite++;
          }
//_____________ Start Audio thread _____________________
          if(audio)
          {          
            pq=new PacketQueue("MP4 audioQ",5000,2*1024*1024);
            memset(&context,0,sizeof(context));
            context.audioEncoder=audio;
            context.audioTargetSample=0xFFFF0000; ; //FIXME
            context.packetQueue=pq;
            // start audio thread
            ADM_assert(!pthread_create(&audioThread,NULL,(THRINP)defaultAudioQueueSlave,&context)); 
            ADM_usleep(4000);
          }
//_____________GO !___________________
           for(int frame=1;frame<total;frame++)
           {
               while(muxer->needAudio())
               {
                    if(pq->Pop(audioBuffer,&alen,&sample))
                    {
                     if(alen)
                     {
                        muxer->writeAudioPacket(alen,audioBuffer,sample_got);
                        totalAudioSize+=alen;
                        encoding_gui->setAudioSize(totalAudioSize);
                        sample_got+=sample;
                     }
                    }else break;
               }
               ADM_assert(_encode);
               bitstream.cleanup(frameWrite);
               if(!prefill || frame+prefill<total) 
               {
                  
                  r=_encode->encode ( prefill+frame, &bitstream);
               }
                else
                {
                    r=_encode->encode ( total-1, &bitstream);
                }
               if(!r && frame<total-2)
               {
                        printf("MP4:Frame %u error\n",frame);
                        GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL);
                        goto  stopit;
                }
                if(!bitstream.len && skipping)
                {
                    printf("Frame skipped (xvid ?)\n");
                    continue;
                }
                sent++;
                skipping=0;
            //    printf("Prefill %u FrameWrite :%u Frame %u PtsFrame :%u\n",prefill,frameWrite,frame,bitstream.ptsFrame);
                frameWrite++;
                muxer->writeVideoPacket( &bitstream);
                encoding_gui->setFrame(frame,bitstream.len,bitstream.out_quantizer,total);
               if(!encoding_gui->isAlive())
                {
                    
                    goto stopit;
                }
               
           }
           ret=1;
           
stopit:
    printf("2nd pass, sent %u frames\n",sent);
    // Flush slave Q
    if(audio)
    {
        context.audioAbort=1;
        pq->Abort();
        // Wait for audio slave to be over
        while(!context.audioDone)
        {
          printf("Waiting Audio thread\n");
          ADM_usleep(500000); 
        }
        delete pq;
    }
    //
           if(muxer) muxer->close();
           if(encoding_gui) delete encoding_gui;
           if(TwoPassLogFile) delete [] TwoPassLogFile;
           if(videoBuffer) delete [] videoBuffer;
           if(muxer) delete muxer;
           if(_encode) delete _encode;	
           if(videoExtraData) delete [] videoExtraData;
           // Cleanup
           deleteAudioFilter (audio);
           return ret;
}
/**
    \fn initVideo
    \brief setup video part of muxer
*/
bool muxerFFmpeg::initVideo(ADM_videoStream *stream)
{
    audioDelay=stream->getVideoDelay();
    video_st = avformat_new_stream(oc, NULL);
	if (!video_st)
	{
		printf("[FF] new stream failed\n");
		return false;
	}
    AVCodecContext *c;
        c = video_st->codec;
        c->sample_aspect_ratio.num=1;
        c->sample_aspect_ratio.den=1;
        video_st->sample_aspect_ratio=c->sample_aspect_ratio;

        uint32_t videoExtraDataSize=0;
        uint8_t  *videoExtraData;
        stream->getExtraData(&videoExtraDataSize,&videoExtraData);
        printf("[FF] Using %d bytes for video extradata\n",(int)videoExtraDataSize);
        ffmpuxerSetExtradata(c,videoExtraDataSize,videoExtraData);

        c->rc_buffer_size=8*1024*224;
        c->rc_max_rate=9500*1000;
        c->rc_min_rate=0;
        c->bit_rate=9000*1000;
        c->codec_type = AVMEDIA_TYPE_VIDEO;
        c->flags=CODEC_FLAG_QSCALE;
        c->width = stream->getWidth();
        c->height =stream->getHeight();
        uint32_t fcc=stream->getFCC();

        if(isMpeg4Compatible(fcc))
        {
                c->codec_id = CODEC_ID_MPEG4;
                if(stream->providePts()==true)
                {
                    c->has_b_frames=1; // in doubt...
                    c->max_b_frames=2;
                }else
                {
                    ADM_warning("Incoming stream does not provide PTS \n");
                    c->has_b_frames=0; // No PTS=cannot handle CTS...
                    c->max_b_frames=0;
                }
        }else
        {
                if(isH264Compatible(fcc) || isH265Compatible(fcc))
                {
                        if(stream->providePts()==true)
                        {
                            c->has_b_frames=1; // in doubt...
                            c->max_b_frames=2;
                        }else
                        {
                            printf("[MP4] Source video has no PTS information, assuming no b frames\n");
                            c->has_b_frames=0; // No PTS=cannot handle CTS...
                            c->max_b_frames=0;
                        }
                        
                        if(isH265Compatible(fcc)) {
                            c->codec_id = AV_CODEC_ID_HEVC;
                             setAvCodec(c,AV_CODEC_ID_HEVC);
                        } else {
                            c->codec_id = CODEC_ID_H264;
                             setAvCodec(c,CODEC_ID_H264);
                        }
                }
                else
                {
                        if(isDVCompatible(fcc))
                        {
                          c->codec_id = CODEC_ID_DVVIDEO;
                        }else
                        {
                          if(fourCC::check(fcc,(uint8_t *)"H263"))
                          {
                                    c->codec_id=CODEC_ID_H263;
                            }else

                           if(isVP6Compatible(stream->getFCC()))
                                {
                                         c->codec_id=CODEC_ID_VP6F;
                                         setAvCodec(c,CODEC_ID_VP6F);
                                         c->has_b_frames=0; // No PTS=cannot handle CTS...
                                         c->max_b_frames=0;
                                }else
                                        if(fourCC::check(stream->getFCC(),(uint8_t *)"FLV1"))
                                        {
                                                c->has_b_frames=0; // No PTS=cannot handle CTS...
                                                c->max_b_frames=0;
                                                c->codec_id=CODEC_ID_FLV1;
                                                setAvCodec(c,CODEC_ID_FLV1);

                                        }else
                                        {
                                            if(fourCC::check(stream->getFCC(),(uint8_t *)"MPEG1"))
                                            {
                                                c->has_b_frames=1; // No PTS=cannot handle CTS...
                                                c->max_b_frames=2;
                                                c->codec_id=CODEC_ID_MPEG1VIDEO;
                                            }
                                            else if(fourCC::check(stream->getFCC(),(uint8_t *)"MPEG2"))
                                            {
                                                c->has_b_frames=1; // No PTS=cannot handle CTS...
                                                c->max_b_frames=2;
                                                c->codec_id=CODEC_ID_MPEG2VIDEO;
                                            }else
                                            {
                                                uint32_t id=stream->getFCC();

                                                AVCodecID cid=ADM_codecIdFindByFourcc(fourCC::tostring(id));
                                                if(cid==CODEC_ID_NONE)
                                                {
                                                    printf("[FF] Unknown video codec\n");
                                                    return false;
                                                }
                                                c->codec_id=cid;
                                            }
                                        }
                        }
                }
        }
        if(useGlobalHeader()==true)
        {
            if(videoExtraDataSize)
            {
                ADM_info("Video has extradata and muxer requires globalHeader, assuming it is done so.\n");
                c->flags|=CODEC_FLAG_GLOBAL_HEADER;
            }else
            {
                ADM_warning("Video has no extradata but muxer requires globalHeader.\n");
            }
        }

        printf("[FF] Video initialized\n");

    return true;
}
void  A_SaveAudioNVideo(char *name)
{
	 uint32_t needSmart=0,fl;
     GenericAviSave	*nw;
     aviInfo info;

     video_body->getVideoInfo(&info);

     printf("\n video process mode : %d",videoProcessMode);
     if (!videoProcessMode)
     {
       			if(video_body->isMultiSeg()) needSmart=1;
          			video_body->getFlags(frameStart,&fl);
             		if(!(fl&AVI_KEY_FRAME)) needSmart=1;

				if(needSmart) printf("\n probably need smart copy mode\n");
    	
    		if( !isMpeg4Compatible(  info.fcc)
#ifdef USE_FFMPEG
			  && !isMSMpeg4Compatible(info.fcc)

#endif      
      			)
             {
                	printf("\n not encodable, cancelling smart mode\n");
                 	needSmart=0;

               }
    			

#ifdef HAVE_ENCODER
			if(needSmart &&
   										GUI_Question("You may need smart copy.\n Enable it ?"))
             		{
                      nw=new   GenericAviSaveSmart;
                 	}
                  else
                  {
                           nw=new   GenericAviSaveCopy;
                    }



#else
     		nw=new   GenericAviSaveCopy;
#endif
       }
       else
       {
#ifdef HAVE_ENCODER
			printf("\n Process mode\n");
     		nw=new   GenericAviSaveProcess;
#else
			GUI_Alert("\n No encoder , cannot save in process mode");
   			return ;
#endif

        }
     if(!nw->saveAvi(name))
     {
        	GUI_Alert(" AVI NOT saved");
       }
       else
        	GUI_Alert(" Saved successfully");

       delete nw;


}
/**
    \fn getDecoder
    \brief returns the correct decoder for a stream w,h,fcc,extraLen,extraData,bpp
*/
decoders *ADM_coreCodecGetDecoder (uint32_t fcc, uint32_t w, uint32_t h, uint32_t extraLen, uint8_t * extraData,uint32_t bpp)
{
  ADM_info("Searching decoder in coreVideoCodec(%d x %d, extradataSize:%d)...\n",w,h,extraLen);
  if (isMSMpeg4Compatible (fcc) == 1)
    {
      return (decoders *) (new decoderFFDiv3 (w,h,fcc,extraLen,extraData,bpp));
    }
  if (isDVCompatible(fcc))//"CDVC"))
    {
      return (decoders *) (new decoderFFDV (w,h,fcc,extraLen,extraData,bpp));
    }
 
  if (fourCC::check (fcc, (uint8_t *) "HFYU"))
    {
      return (decoders *) (new decoderFFhuff (w,h,fcc,extraLen,extraData,bpp));
    }
  if (fourCC::check (fcc, (uint8_t *) "PNG "))
    {
      return (decoders *) (new decoderFFPng (w,h,fcc,extraLen,extraData,bpp));
    }
  if (fourCC::check (fcc, (uint8_t *) "FFVH"))
    {
      return (decoders *) (new decoderFF_ffhuff (w,h,fcc,extraLen,extraData,bpp));
    }
 

  if (isH264Compatible (fcc))
    {
#if defined(USE_VDPAU) && 0
        if(vdpauUsable()==true)
            return (decoders *) (new decoderFFVDPAU (w,h,fcc,extraLen,extraData,bpp));
        else
#endif
            return (decoders *) (new decoderFFH264 (w,h,fcc,extraLen,extraData,bpp));
    }


/*
	Could be either divx5 packed crap or xvid or ffmpeg
	For now we return FFmpeg and later will switch to divx5 if available
		(ugly hack for ugly hack....)
*/

  if (isMpeg4Compatible (fcc) == 1)
    {
      return (decoders *) (new decoderFFMpeg4 (w,h,fcc,extraLen,extraData,bpp));
    }
  if (fourCC::check (fcc, (uint8_t *) "YV12")
      || fourCC::check (fcc, (uint8_t *) "yv12")
      || fourCC::check (fcc, (uint8_t *) "I420"))
    {
      printf ("\n using null codec\n");
      return (decoders *) (new decoderNull (w,h,fcc,extraLen,extraData,bpp));
    }
  if (fourCC::check (fcc, (uint8_t *) "UYVY"))
    {
      printf ("\n using uyvy codec\n");
      return (decoders *) (new decoderUYVY (w,h,fcc,extraLen,extraData,bpp));
    }
  if (fourCC::check (fcc, (uint8_t *) "YUY2"))
    {
      printf ("\n using YUY2 codec\n");
      return (decoders *) (new decoderYUY2 (w,h,fcc,extraLen,extraData,bpp));
    } 
  if ((fcc == 0) || fourCC::check (fcc, (uint8_t *) "RGB "))
    {
      // RGB 16 Codecs
      printf ("\n using RGB codec\n");
      return (decoders *) (new decoderRGB16 (w,h,fcc,extraLen,extraData,bpp)); //1

    }
 if ((fcc == 0) || fourCC::check (fcc, (uint8_t *) "DIB "))
    {
      // RGB 16 Codecs
      printf ("\n using DIB codec (%d bpp)\n",(int)bpp);
      return (decoders *) (new decoderRGB16 (w,h,fcc,extraLen,extraData,bpp));  //0

    }
  if (isMpeg12Compatible (fcc))
	  return (decoders *) (new decoderFFMpeg12 (w,h,fcc,extraLen,extraData,bpp));

    // Search ffsimple
    decoders *dec=admCreateFFSimple(w,h,fcc,extraLen,extraData,bpp);
    if(dec)
    {
        printf("using ffSimple\n");
        return dec;
    }

  // default : null decoder
  printf ("\n using invalid codec for \n");
  fourCC::print (fcc);

  return (decoders *) (new decoderEmpty(w,h,fcc,extraLen,extraData,bpp));
}
bool muxerMP4::open(const char *file, ADM_videoStream *s,uint32_t nbAudioTrack,ADM_audioStream **a)
{
    if(!isMpeg4Compatible(s->getFCC()) && !isH264Compatible(s->getFCC()))
    {
        GUI_Error_HIG("Unsupported","Only MP4Video & H264 supported for video");
        return false;
    }
    if(nbAudioTrack)
        for(int i=0; i<nbAudioTrack; i++)
        {
            uint32_t acc=a[i]->getInfo()->encoding;
            if(acc!=WAV_MP2 && acc!=WAV_MP3 && acc!=WAV_AAC)
            {
                GUI_Error_HIG("Unsupported","Only AAC & mpegaudio supported for audio");
                return false;
            }
        }
    /* All seems fine, open stuff */
    const char *f="mp4";
    if(muxerConfig.muxerType==MP4_MUXER_PSP) f="psp";
    if(false==setupMuxer(f,file))
    {
        printf("[MP4] Failed to open muxer\n");
        return false;
    }

    if(initVideo(s)==false)
    {
        printf("[MP4] Failed to init video\n");
        return false;
    }


    AVCodecContext *c;
    AVRational myTimeBase;
    c = video_st->codec;
    rescaleFps(s->getAvgFps1000(),&(c->time_base));
    myTimeBase=video_st->time_base=c->time_base;
    ADM_info("Video stream time base :%d,%d\n",video_st->time_base.num,video_st->time_base.den);
    c->gop_size=15;

    if(initAudio(nbAudioTrack,a)==false)
    {
        printf("[MP4] Failed to init audio\n");
        return false;
    }

    // /audio
    int er = avio_open(&(oc->pb), file, AVIO_FLAG_WRITE);


    ADM_info("Timebase In  = %d/%d\n",myTimeBase.num,myTimeBase.den);

    if (er)
    {
        ADM_error("[Mp4]: Failed to open file :%s, er=%d\n",file,er);
        return false;
    }

    AVDictionary *dict = NULL;
    char buf[64];

    snprintf(buf, sizeof(buf), "%d", AV_TIME_BASE / 10);
    av_dict_set(&dict, "preload", buf, 0);
    av_dict_set(&dict, "max_delay", "200000", 0);
    av_dict_set(&dict, "muxrate", "10080000", 0);
#ifndef _WIN32 // does not work on windows as the file must be opened twice at the same time        
    av_dict_set(&dict, "movflags","faststart",0);
#endif
    ADM_assert(avformat_write_header(oc, &dict) >= 0);

    ADM_info("Timebase codec = %d/%d\n",c->time_base.num,c->time_base.den);
    ADM_info("Timebase stream = %d/%d\n",video_st->time_base.num,video_st->time_base.den);
    if(myTimeBase.den==video_st->time_base.den && video_st->time_base.num==1)
    {
        roundup=myTimeBase.num;
        ADM_warning("Timebase roundup = %d\n",roundup);

    }
    av_dict_free(&dict);
    vStream=s;
    aStreams=a;
    nbAStreams=nbAudioTrack;
    initialized=true;
    return true;
}