/**
    \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 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;
}
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;
}
/**
     \fn bFrameDroppable
*/
static bool bFrameDroppable(uint32_t fcc)
{
    if(isH264Compatible(fcc)) return false;
    return true;
}
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;
}
/**
    \fn getDecoder
    \brief returns the correct decoder for a stream w,h,fcc,extraLen,extraData,bpp
*/
decoders *ADM_getDecoder (uint32_t fcc, uint32_t w, uint32_t h, uint32_t extraLen, 
            uint8_t * extraData,uint32_t bpp)
{
  ADM_info("\nSearching decoder in plugins\n");
  decoders *fromPlugin=tryCreatingVideoDecoder(w,h,fcc,extraLen,extraData,bpp);
  if(fromPlugin) return fromPlugin;
  
#if defined(USE_VDPAU) 
  ADM_info("Searching decoder in vdpau (%d x %d, extradataSize:%d)...\n",w,h,extraLen);
  if (isH264Compatible (fcc) || isMpeg12Compatible(fcc) || 1*isVC1Compatible(fcc))
    {
        ADM_info("This is vdpau compatible\n");
        if(true==vdpauUsable())
        {
            decoderFFVDPAU *dec=new decoderFFVDPAU (w,h,fcc,extraLen,extraData,bpp);
            if(dec->initializedOk()==true)
                return (decoders *) (dec);
            else
            {
                GUI_Error_HIG("VDPAU","Cannot initialize VDPAU, make sure it is not already used by another application.\nSwitching to default decoder.");
                delete dec;
            }
        }else ADM_info("Vdpau is not active\n");
    }        
#endif // VDPAU
  

#if defined(USE_XVBA) 
  ADM_info("Searching decoder in xvba (%d x %d, extradataSize:%d)...\n",w,h,extraLen);
  if (isH264Compatible (fcc) )
    {
        ADM_info("This is xvba compatible\n");
        if(true==xvbaUsable())
        {
            decoderFFXVBA *dec=new decoderFFXVBA (w,h,fcc,extraLen,extraData,bpp);
            if(dec->initializedOk()==true)
                return (decoders *) (dec);
            else
            {
                GUI_Error_HIG("XVBA","Cannot initialize XVBA, make sure it is not already used by another application.\nSwitching to default decoder.");
                delete dec;
            }
        }else ADM_info("XVBA is not active\n");
    }        
#endif // XVBA  
#if defined(USE_LIBVA) 
  ADM_info("Searching decoder in libva (%d x %d, extradataSize:%d)...\n",w,h,extraLen);
  if (isH264Compatible (fcc) )
    {
        ADM_info("This is libva compatible\n");
        if(true==libvaUsable())
        {
            decoderFFLIBVA *dec=new decoderFFLIBVA (w,h,fcc,extraLen,extraData,bpp);
            if(dec->initializedOk()==true)
                return (decoders *) (dec);
            else
            {
                GUI_Error_HIG("LIBVA","Cannot initialize LIBVA, make sure it is not already used by another application.\nSwitching to default decoder.");
                delete dec;
            }
        }else ADM_info("LIBVA is not active\n");
    }        
#endif // XVBA  
  
  
    ADM_info("Searching decoder in coreVideoCodec(%d x %d, extradataSize:%d)...\n",w,h,extraLen);
    return ADM_coreCodecGetDecoder(fcc,w,h,extraLen,extraData,bpp);
}
/**
    \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;
}
/**
    \fn setupVideo
    \brief prepare video (copy or process)
*/
ADM_videoStream *admSaver::setupVideo(void)
{
    ADM_videoStream *video=NULL;
    // Video Stream
    if(!videoEncoderIndex) // Copy
    {
        aviInfo info;
        video_body->getVideoInfo(&info);

        uint8_t *extra;
        uint32_t extraLen;
        video_body->getExtraHeaderData(&extraLen,&extra);
//#warning do something better
        ADM_videoStreamCopy *copy=NULL;
        if(isH264Compatible(info.fcc))
        {
            if(muxer->preferH264AnnexB())
            {
                ADM_info("The video stream is H264\n");
                ADM_info("The muxer prefers AnnexB H264 bitstream\n");
            }
        }
        if(isH264Compatible(info.fcc) && !extraLen && !muxer->preferH264AnnexB())
        {
            ADM_info("Probably AnnexB bitstream\n");
            copy=new ADM_videoStreamCopyFromAnnexB(markerA,markerB);
        }else   
        {
            copy=new ADM_videoStreamCopy(markerA,markerB);
        }
        video=copy;
        // In that case, get the real time and update audio with it...
        // Because we might have go back in time to catch the first intra
        startAudioTime=copy->getStartTime();
      
        
    }else
    {
        // 1- create filter chain
        //******************************

        chain=createVideoFilterChain(markerA,markerB);
        if(!chain)
        {
                GUI_Error_HIG("Video","Cannot instantiante video Chain");
                return NULL;
        }
        // 2- Create Encoder
        //********************
        int sz=chain->size();
        ADM_assert(sz);
        ADM_coreVideoFilter  *last;
        last=(*chain)[sz-1]; // Grab last filter
        ADM_coreVideoEncoder *encoder=createVideoEncoderFromIndex(last,videoEncoderIndex,muxer->useGlobalHeader()); // FIXME GLOBAL HEADERS
        if(!encoder)
        {
           GUI_Error_HIG("Video","Cannot create encoder");
           return NULL;
        }
        // 3 dual Pass ?
        //*****************
        if(encoder->isDualPass())
        {
            encoder=handleFirstPass(encoder); // Do pass 1 and switch to pass 2
            if(!encoder)
            {
                printf("[Save] cannot create encoder for pass 2\n");
                return NULL;
            }
        }
        if(encoder->setup()==false)
        {
            GUI_Error_HIG("Video","Cannot setup codec. Bitrate too low ?");
            delete encoder;
            encoder=NULL;
            return NULL;
        }
        video= new ADM_videoStreamProcess(encoder);
        if(!video)
        {
                GUI_Error_HIG("Video","Cannot create encoder");
                delete encoder;
                return NULL;
        }
    }  
    return video;
}
/**
    \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;
}