//________________________________________________
//   Beginning of the write process
//   We fill-in the headers
//	2- Write video headers
//_______________________________________________
uint8_t aviWrite::writeVideoHeader( uint8_t *extra, uint32_t extraLen )
{

  assert (_out);

      _videostream.fccType = fourCC::get ((uint8_t *) "vids");
      _bih.biSize=sizeof(_bih)+extraLen;
#ifdef ADM_BIG_ENDIAN
	// in case of Little endian, do the usual swap crap
	
	AVIStreamHeader as;
	BITMAPINFOHEADER b;
	memcpy(&as,&_videostream,sizeof(as));
	Endian_AviStreamHeader(&as);		
	memcpy(&b,&_bih,sizeof(_bih));
	Endian_BitMapInfo( &b );
  	setStreamInfo (_out, (uint8_t *) &as,
		  (uint8_t *)&b,sizeof(BITMAPINFOHEADER),
		  extra,extraLen, 	 
		 0x1000);
#else
  	setStreamInfo (_out, (uint8_t *) &_videostream,
		  (uint8_t *)&_bih,sizeof(BITMAPINFOHEADER),
		  extra,extraLen, 	 
		 0x1000);

#endif
	return 1;
}
//________________________________________________
//   Beginning of the write process
//   We fill-in the headers
//	2- Write video headers
//_______________________________________________
uint8_t aviWrite::writeVideoHeader( uint8_t *extra, uint32_t extraLen )
{

  ADM_assert (_file);

      _videostream.fccType = fourCC::get ((uint8_t *) "vids");
      _bih.biSize=sizeof(_bih)+extraLen;
	// MOD Feb 2005 by GMV: video super index length
	uint32_t odml_video_super_idx_size;
        if(doODML!=NORMAL)
        {
            
            odml_video_super_idx_size=24+odml_default_nbrof_index*16;
        }else
        {
            odml_video_super_idx_size=24+odml_indexes[0].odml_nbrof_index*16;
        }
	// END MOD Feb 2005 by GMV
#ifdef ADM_BIG_ENDIAN
	// in case of Little endian, do the usual swap crap
	
	AVIStreamHeader as;
	BITMAPINFOHEADER b;
	memcpy(&as,&_videostream,sizeof(as));
	Endian_AviStreamHeader(&as);		
	memcpy(&b,&_bih,sizeof(_bih));
	Endian_BitMapInfo( &b );
  	setStreamInfo (_file, (uint8_t *) &as,
		  (uint8_t *)&b,sizeof(BITMAPINFOHEADER),
		// MOD Feb 2005 by GMV: ODML support
		odml_video_super_idx_size,0,
		// END MOD Feb 2005 by GMV
		  extra,extraLen, 	 
		 0x1000);
#else
  	setStreamInfo (_file, (uint8_t *) &_videostream,
		  (uint8_t *)&_bih,sizeof(ADM_BITMAPINFOHEADER),
		// MOD Feb 2005 by GMV: ODML support
		odml_video_super_idx_size,0,
		// END MOD Feb 2005 by GMV
		  extra,extraLen, 	 
		 0x1000);

#endif
	return 1;
}
//______________________________________
//
// Open and get the headears/index built
// along way
//______________________________________
uint8_t    OpenDMLHeader::open(const char *name)
{
uint8_t badAvi=0;
uint32_t rd;

	printf("** opening OpenDML files **");	
        
	_fd=fopen(name,"rb");
	if(!_fd)
	{
		printf("\n cannot open %s \n",name);
		return 0;
	}
        myName=ADM_strdup(name);
#define CLR(x)              memset(& x,0,sizeof(  x));

              CLR( _videostream);
              CLR( _mainaviheader);
	      _isvideopresent=1;
	      _isaudiopresent=0;    	     	      	 	      
	      
		_nbTrack=0;
		riffParser *parser=new riffParser(name);
		
		if(MKFCC('R','I','F','F')!=(rd=parser->read32()))
			{
				printf("Not riff\n");badAvi=1;
				printf("%lx != %lx\n",rd,MKFCC('R','I','F','F'));
			}
		parser->read32();
		if(MKFCC('A','V','I',' ')!=parser->read32())
			{
				printf("Not Avi\n");badAvi=1;
			}
		
		if(!badAvi)
			{
				walk(parser);	
			
			}					
		delete parser;
		aprintf("Found %d tracks\n:-----------\n",_nbTrack);
		// check if it looks like a correct avi
		if(!_nbTrack) badAvi=1;
		
		// if we are up to here -> good avi :)
		if(badAvi)
		{
			printf("FAIL\n");
			return 0;
		}
		// now read up each parts...
		//____________________________
		
#ifdef __WIN32
                
#define DUMP_TRACK(i) aprintf(" at %I64u (%I64x) size : %I64u (%I64x)\n", \
                                _Tracks[i].strh.offset,\
                                _Tracks[i].strh.offset,\
                                _Tracks[i].strh.size,\
                                _Tracks[i].strh.size);

#else
                
#define DUMP_TRACK(i) aprintf(" at %llu (%llx) size : %llu (%llx)\n", \
				_Tracks[i].strh.offset,\
				_Tracks[i].strh.offset,\
				_Tracks[i].strh.size,\
				_Tracks[i].strh.size);
#endif								
		for(uint32_t i=0;i<_nbTrack;i++)
		{
			DUMP_TRACK(i);		
		}		
		
		uint32_t vidTrack=0xff;
		// search wich track is the video one
		// and load it to _videoheader
		
		for(uint32_t i=0;i<_nbTrack;i++)
		{
			fseeko(_fd,_Tracks[i].strh.offset,SEEK_SET);
			if(_Tracks[i].strh.size!=sizeof(_videostream))
			{
				printf("Mmm(1) we have a bogey here, size mismatch : %"LLU"\n",_Tracks[i].strh.size);
				printf("expected %d\n",sizeof(_videostream));
				if(_Tracks[i].strh.size<sizeof(_videostream)-8) // RECT is not mandatory
				{
                                  GUI_Error_HIG(QT_TR_NOOP("Malformed header"), NULL);
					return 0;
				}		
				printf("Trying to continue anyway\n");			
			}
			fread(&_videostream,sizeof(_videostream),1,_fd);
#ifdef ADM_BIG_ENDIAN
				Endian_AviStreamHeader(&_videostream);
#endif
			if(_videostream.fccType==MKFCC('v','i','d','s'))
				{
					vidTrack=i;
					printf("Video track is %ld\n",i);
					break;
				}		
		}
		if(0xff==vidTrack)
		{
			printf("Could not identify video track!");
			return 0;
		}
		
		// STOP HERE -> Alex <-
		//return 0;
		// STOP HERE -> Alex <-
		
		
		
									

		// then bih stuff
		int32_t extra;
//		_fd=fopen(name,"rb");
		
		fseeko(_fd,_Tracks[vidTrack].strf.offset,SEEK_SET);		
		extra=_Tracks[vidTrack].strf.size-sizeof(_video_bih);
		if(extra<0)
		{	
			printf("bih is not big enough (%lu/%lu)!\n",_Tracks[vidTrack].strf.size,sizeof(_video_bih));
			return 0;
		}
		fread(&_video_bih,sizeof(_video_bih),1,_fd);
#ifdef ADM_BIG_ENDIAN
		Endian_BitMapInfo(&_video_bih);
#endif
		if(extra>0)
		{				
			_videoExtraLen=extra;		
			_videoExtraData=new uint8_t [extra];
			fread(_videoExtraData,extra,1,_fd);
		}
		_isvideopresent=1;
		//--------------------------------------------------
		//	Read audio trak info, select if there is
		//	several
		//--------------------------------------------------
		// and audio track
		if(_mainaviheader.dwStreams>=2)
		{
			// which one is the audio track, is there several ?
			if(!(_nbAudioTracks=countAudioTrack()))
                        {
                                printf("Weird, there is no audio track, but more than one stream...\n");
                        }			
                        else
                        {
                          uint32_t run=0,audio=0;
                          odmlAudioTrack *track;

                          _audioTracks=new odmlAudioTrack[_nbAudioTracks]; 
                          while(audio<_nbAudioTracks)
                          {
                                        ADM_assert(run<_nbTrack);

                                        track=&(_audioTracks[audio]);
                                        fseeko(_fd,_Tracks[run].strh.offset,SEEK_SET);
                                        if(_Tracks[run].strh.size != sizeof(_audiostream))
                                        {
                                                printf("Mmm(2) we have a bogey here, size mismatch : %"LLU"\n",_Tracks[run].strh.size);
                                                printf("expected %d\n",sizeof(_audiostream));
                                                if(_Tracks[run].strh.size<sizeof(_audiostream)-8)
                                                {
                                                  GUI_Error_HIG(QT_TR_NOOP("Malformed header"), NULL);
                                                        return 0;
                                                }
                                                printf("Trying to continue anyway\n");			
                                        }
                                        fread(track->avistream,sizeof(_audiostream),1,_fd);
#ifdef ADM_BIG_ENDIAN
                                        Endian_AviStreamHeader(track->avistream);
#endif
                                        if(track->avistream->fccType!=MKFCC('a','u','d','s'))
                                        {	
                                                printf("Not an audio track!\n");
                                                run++;
                                                continue;
                                        }
                                        // now read extra stuff
                                        fseeko(_fd,_Tracks[run].strf.offset,SEEK_SET);		
                                        extra=_Tracks[run].strf.size-sizeof(WAVHeader);
                                        if(extra<0)
                                        {	
                                                printf("WavHeader is not big enough (%lu/%lu)!\n",
                                                _Tracks[run].strf.size,sizeof(WAVHeader));
                                                return 0;
                                        }
                                        fread(track->wavHeader,sizeof(WAVHeader),1,_fd);				
#ifdef ADM_BIG_ENDIAN
                                        Endian_WavHeader(track->wavHeader);
#endif
                                        if(extra>2)
                                        {
                                                fgetc(_fd);fgetc(_fd);
                                                extra-=2;
                                                track->extraDataLen=extra;		
                                                track->extraData=new uint8_t [extra];
                                                fread(track->extraData,extra,1,_fd);
                                        }
                                        track->trackNum=run;
                                        audio++;
                                        run++;
                           }	
                        }
                }
		
		// now look at the index stuff
		// there could be 3 cases:
		// 1- It is a openDML index, meta index  + several smaller index
		// 2- It is a legacy index (type 1 , most common)
		// 3- It is a broken index or no index at all
		//
		// If it is a openDML index we will find a "indx" field in the Tracks
		// Else we will find it in _regularIndex Track
		// Since openDML often also have a regular index we will try open DML first
		
		uint8_t ret=0;
		Dump();
		
		// take the size of riff header and actual file size
		uint64_t riffSize;
		fseeko(_fd,0,SEEK_END);		
		_fileSize=ftello(_fd);
		fseeko(_fd,0,SEEK_SET);
		read32();
		riffSize=(uint64_t )read32();
				
		
		// 1st case, we have an avi < 4 Gb
		// potentially avi type 1	
#if 0	
		if((_fileSize<4*1024*1024*1024LL)&&
                	// if riff size is ~ fileSize try regular index
			 (abs(riffSize-_fileSize)<1024*1024))
#endif

#define HAS(x) if(x) printf(#x" : yes\n"); else printf(#x" : no\n");
                // If there is no openDML index
                HAS( _regularIndex.offset);
                HAS( _Tracks[vidTrack].indx.offset);
                if(!ret && _regularIndex.offset &&!_Tracks[vidTrack].indx.offset) 
        // try regular avi if a idx1 field is there (avi index)
                        ret=indexRegular(vidTrack);

                if (!ret && _Tracks[vidTrack].indx.offset)	// Try openDML if a index field is there (openDML)
                        ret=indexODML(vidTrack);
                if(!ret) 
                {
                        printf("Could not index it properly...\n");
                        return 0;

                }
                if(!_nbAudioTracks)
                {
                         _isaudiopresent=0;
                }
                else
                {
                        // build audio stream
                        odmlAudioTrack *track;
                        // Check it is not a weird DV file
                        if(fourCC::check(_video_bih.biCompression,(uint8_t *)"dvsd"))
                        {
                             for(int i=0;i<_nbAudioTracks;i++)
                             {
                                    track=&(_audioTracks[i]);
                                    WAVHeader *hdr=  track->wavHeader;
                                    if(!hdr->frequency)
                                    {
                                            printf("Fixing audio track to be PCM\n");
                                            hdr->frequency=48000;
                                            //hdr->channels=2;
                                            hdr->byterate=48000*hdr->channels*2;
                                            hdr->blockalign=2*hdr->channels;
                                    }
                             }

                        }
                        for(int i=0;i<_nbAudioTracks;i++)
                        {
                                track=&(_audioTracks[i]);
                                _audioTracks[i].track= new AVDMAviAudioStream(track->index,
                                                track->nbChunks,
                                                myName,
                                                track->wavHeader,
                                                0,
                                                track->extraDataLen,track->extraData);
                        }
                }

				if (!_video_bih.biCompression && fourCC::check(_videostream.fccHandler,(uint8_t*)"DIB "))
				{
					// flip video
					uint8_t *extraData = new uint8_t[_videoExtraLen + 9];

					memcpy(extraData, _videoExtraData, _videoExtraLen);
					memcpy(extraData + _videoExtraLen, "BottomUp", 9);
										
					delete [] _videoExtraData;

					_videoExtraLen += 9;
					_videoExtraData = extraData;

					_videostream.fccHandler = _video_bih.biCompression = fourCC::get((uint8_t*)"DIB ");
				}
				else				
					_videostream.fccHandler=_video_bih.biCompression;

                printf("\nOpenDML file successfully read..\n");
                return ret;
}
uint8_t    picHeader::open(char *inname)
{

uint32_t		nnum;
uint32_t		*fcc;
uint8_t			fcc_tab[4];
FILE 			*fd;
char 			*end;
uint32_t			w=0,h=0;

	// 1- identity the file type
	//
	fcc=(uint32_t *)fcc_tab;
	fd=fopen(inname,"rb");
	if(!fd)
		{
			printf("\n Cannot open that file!\n");
			return 0;
		}
	fread(fcc_tab,4,1,fd);
	fclose(fd);
	if(fourCC::check(*fcc,(uint8_t *)"RIFF"))
	{
		_type=PIC_BMP;
		printf("\n It looks like BMP (RIFF)...\n");
	}
	else
	{
		if(fcc_tab[0]=='B' && fcc_tab[1]=='M')
		{
			_type=PIC_BMP2;
			printf("\n It looks like BMP (BM)...\n");
		}
		else	
		if(fcc_tab[0]==0xff && fcc_tab[1]==0xd8)
		{
		 	_type=PIC_JPEG;
			printf("\n It looks like Jpg...\n");
		}
		else
		{
			printf("\n Cannot identify file (%x %x)\n",*fcc,*fcc&0xffff);
			return 0;
		}
	}

	// Then spit the name in name and extension
	char *name;
	char *extension;
	 PathSplit(inname, &name, &extension);


     	nnum=1;

     	end=name+strlen(name)-1;
     	while(( *end>='0') && (*end<='9'))
     		{
            		end--;
        	      	nnum++;
         	};
      if(nnum==1)
      	{
          	printf("\n only one file!");
          	return 0;

         }
        nnum--;
        end++;
       _first=atoi(end);
       printf("\n First : %lu, num digit :%lu",_first,nnum);
       *(end)=0;
       printf("\n Path : %s\n",name);

       char realname[250];
       char realstring[250];

            	sprintf(realstring,"%%s%%0%lud.%s",nnum,extension);
              printf("\n string : %s",realstring);

       _nb_file=0;

       for(uint32_t i=0;i<MAX_ACCEPTED_OPEN_FILE;i++)
       	{
              sprintf(realname,realstring,name,i+_first);
              printf("\n %lu : %s",i,realname);
              fd=fopen(realname,"rb");
              if(fd==NULL) break;
              fclose(fd);
              _nb_file++;
          }
	printf("\n found %lu images\n",_nb_file);


	_fd=(FILE **)ADM_alloc(_nb_file*sizeof(FILE*));
	_imgSize=new uint32_t[_nb_file];
	  //_________________________________
          // now open them and assign fd && imgSize
	  //__________________________________
          for(uint32_t i=0;i<_nb_file;i++)
          {
              sprintf(realname,realstring,name,i+_first);
              printf("\n %lu : %s",i,realname);
              _fd[i]=fopen(realname,"rb");
	      fseek(_fd[i],0,SEEK_END);
	      _imgSize[i]=ftell( _fd[i] );
		fseek(_fd[i],0,SEEK_SET);
              ADM_assert(_fd[i]!=NULL);
            }

	delete [] name;
	delete [] extension;


	//
	//	Image is bmp type
	//________________________
	switch(_type)
	{
		case PIC_BMP:
			{
			BITMAPHEADER bmph;

              		fread(&s16,2,1, _fd[0]);
              		if(s16!=0x4D42)
              		{
                		printf("\n incorrect bmp sig.\n");
              			return 0;
               		}
              		fread(&s32,4,1, _fd[0]);
              		fread(&s32,4,1, _fd[0]);
              		fread(&s32,4,1, _fd[0]);
               		fread(&bmph, sizeof(bmph), 1, _fd[0]);
               		if(bmph.compressionScheme!=0)
               		{
                 		printf("\ncannot handle compressed bmp\n");
	               		return 0;
                	}
              		_offset=bmph.size+14;
			w=bmph.width ;
			h=bmph.height ;
			}
			break;
	

		 // Jpeg : Grab the size
		//____________________
		case PIC_JPEG:
			{
			uint16_t tag=0,count=0,off;

			_offset=0;
			fseek(_fd[0],0,SEEK_SET);
			read16(_fd[0]); // skip jpeg ffd8
			while(count<10 && tag!=0xFFC0)
			{

				tag=read16(_fd[0]);
				if( (tag >>8 ) !=0xff)
				{
					printf("invalid jpeg tag found (%x)\n",tag);
				}
				if(tag==0xFFC0)
				{
					read16(_fd[0]); // size
					read8(_fd[0]);  // precision
					h=read16(_fd[0]);
					w=read16(_fd[0]);
				}
				else
				{

					off=read16(_fd[0]);
					if(off<2)
						{
							printf("Offset too short!\n");
							return 0;
						}
					aprintf("Found tag : %x , jumping %d bytes\n",tag,off);
					fseek(_fd[0],off-2,SEEK_CUR);
				}
				count++;
			}
			if(tag!=0xffc0)
			{
				printf("Cannot fint start of frame\n");
				return 0;
			}
			printf("\n %lu x %lu..\n",w,h);
			}
			break;

		case PIC_BMP2:
			{
			BITMAPINFOHEADER bmph;

			fseek(_fd[0],10,SEEK_SET);

			#define MK32() (fcc_tab[0]+(fcc_tab[1]<<8)+(fcc_tab[2]<<16)+ \
						(fcc_tab[3]<<24))

              		fread(fcc_tab,4,1, _fd[0]);
              		_offset=MK32();
			// size, width height follow as int32 
               		fread(&bmph, sizeof(bmph), 1, _fd[0]);
#ifdef ADM_BIG_ENDIAN
			Endian_BitMapInfo(&bmph);	
#endif
               		if(bmph.biCompression!=0)
               		{
                 		printf("\ncannot handle compressed bmp\n");
	               		return 0;
                	}
			w=bmph.biWidth ;
			h=bmph.biHeight ;
			printf("W: %d H: %d offset : %d\n",w,h,_offset);
			}
	
			break;
		default:
			ADM_assert(0);
		}

//_______________________________________
//		Now build header info
//_______________________________________
	      _isaudiopresent=0; // Remove audio ATM
              _isvideopresent=1; // Remove audio ATM

#define CLR(x)              memset(& x,0,sizeof(  x));

               CLR( _videostream);
               CLR(  _mainaviheader);

    			_videostream.dwScale=1;
              _videostream.dwRate=25;
              _mainaviheader.dwMicroSecPerFrame=40000;;     // 25 fps hard coded
              _videostream.fccType=fourCC::get((uint8_t *)"vids");

               _video_bih.biBitCount=24;

              _videostream.dwLength= _mainaviheader.dwTotalFrames=_nb_file;
               _videostream.dwInitialFrames= 0;
               _videostream.dwStart= 0;
               //
               //_video_bih.biCompression= 24;
               //
               _video_bih.biWidth=_mainaviheader.dwWidth		=w ;
               _video_bih.biHeight=_mainaviheader.dwHeight	=h;
               //_video_bih.biPlanes= 24;

	         if(PIC_JPEG==_type)
		 {
			          _video_bih.biCompression=_videostream.fccHandler=fourCC::get((uint8_t *)"MJPG");;
		 }
		 else
		 {
  				_video_bih.biCompression=_videostream.fccHandler=0;
		 }
		printf("Offset : %lu\n",_offset);
       return 1;
}
//______________________________________
//
// Open and get the headears/index built
// along way
//______________________________________
uint8_t    OpenDMLHeader::open(char *name)
{
uint8_t badAvi=0;
uint32_t rd;

	printf("** opening OpenDML files **");	
	_fd=fopen(name,"rb");
	if(!_fd)
	{
		printf("\n cannot open %s \n",name);
		return 0;
	}
#define CLR(x)              memset(& x,0,sizeof(  x));

              CLR( _videostream);
              CLR( _mainaviheader);
	      _isvideopresent=1;
	      _isaudiopresent=0;    	     	      	 	      
	      
		_nbTrack=0;
		riffParser *parser=new riffParser(name);
		
		if(MKFCC('R','I','F','F')!=(rd=parser->read32()))
			{
				printf("Not riff\n");badAvi=1;
				printf("%lx != %lx\n",rd,MKFCC('R','I','F','F'));
			}
		parser->read32();
		if(MKFCC('A','V','I',' ')!=parser->read32())
			{
				printf("Not Avi\n");badAvi=1;
			}
		
		if(!badAvi)
			{
				walk(parser);	
			
			}					
		delete parser;
		aprintf("Found %d tracks\n:-----------\n",_nbTrack);
		// check if it looks like a correct avi
		if(!_nbTrack) badAvi=1;
		
		// if we are up to here -> good avi :)
		if(badAvi)
		{
			printf("FAIL\n");
			return 0;
		}
		// now read up each parts...
		//____________________________
		
#define DUMP_TRACK(i) aprintf(" at %llu (%llx) size : %llu (%llx)\n", \
				_Tracks[i].strh.offset,\
				_Tracks[i].strh.offset,\
				_Tracks[i].strh.size,\
				_Tracks[i].strh.size);
								
		for(uint32_t i=0;i<_nbTrack;i++)
		{
			DUMP_TRACK(i);		
		}		
		
		uint32_t vidTrack=0xff;
		// search wich track is the video one
		// and load it to _videoheader
		
		for(uint32_t i=0;i<_nbTrack;i++)
		{
			fseeko(_fd,_Tracks[i].strh.offset,SEEK_SET);
			if(_Tracks[i].strh.size!=sizeof(_videostream))
			{
				printf("Mmm(1) we have a bogey here, size mismatch : %lu \n",_Tracks[i].strh.size);
				printf("expected %d\n",sizeof(_videostream));
				if(_Tracks[i].strh.size<sizeof(_videostream)-8) // RECT is not mandatory
				{
					GUI_Alert("Maformed header!");
					return 0;
				}		
				printf("Trying to continue anyway\n");			
			}
			fread(&_videostream,sizeof(_videostream),1,_fd);
#ifdef ADM_BIG_ENDIAN
				Endian_AviStreamHeader(&_videostream);
#endif
			if(_videostream.fccType==MKFCC('v','i','d','s'))
				{
					vidTrack=i;
					printf("Video track is %ld\n",i);
					break;
				}		
		}
		if(0xff==vidTrack)
		{
			printf("Could not identify video track!");
			return 0;
		}
		
		// STOP HERE -> Alex <-
		//return 0;
		// STOP HERE -> Alex <-
		
		
		
									

		// then bih stuff
		int32_t extra;
		_fd=fopen(name,"rb");
		
		fseeko(_fd,_Tracks[vidTrack].strf.offset,SEEK_SET);		
		extra=_Tracks[vidTrack].strf.size-sizeof(_video_bih);
		if(extra<0)
		{	
			printf("bih is not big enough (%lu/%lu)!\n",_Tracks[vidTrack].strf.size,sizeof(_video_bih));
			return 0;
		}
		fread(&_video_bih,sizeof(_video_bih),1,_fd);
#ifdef ADM_BIG_ENDIAN
		Endian_BitMapInfo(&_video_bih);
#endif
		if(extra>0)
		{				
			_videoExtraLen=extra;		
			_videoExtraData=new uint8_t [extra];
			fread(_videoExtraData,extra,1,_fd);
		}
		_isvideopresent=1;
		//--------------------------------------------------
		//	Read audio trak info, select if there is
		//	several
		//--------------------------------------------------
		// and audio track
		uint32_t audioTrack=0xff;	
		uint32_t audioTrackNumber=0;
		if(_mainaviheader.dwStreams>=2)
		{
			// which one is the audio track, is there several ?
			switch(countAudioTrack())
			{
				case 0: printf("No audio track found.\n");
					break;
				case 1: printf("One audio track found\n");
					audioTrack=searchAudioTrack(0);
					audioTrackNumber=0;
					break;
				default: printf("Several audio tracks found\n");
					uint32_t t;
					t=GUI_Question("Take second audio track ?");
					audioTrackNumber=t;
					audioTrack=searchAudioTrack(t);
			}
			if(audioTrack!=0xff) // one is marked
			{
				// Read information
				printf("Taking audio track : %lu %lu\n",audioTrackNumber,audioTrack);
				_isaudiopresent=1;
				fseeko(_fd,_Tracks[audioTrack].strh.offset,SEEK_SET);

				if(_Tracks[audioTrack].strh.size!=sizeof(_audiostream));
				{
				
					printf("Mmm(2) we have a bogey here, size mismatch : %lu \n"
						,_Tracks[audioTrack].strh.size);
					printf("expected %d\n",sizeof(_audiostream));
					if(_Tracks[audioTrack].strh.size<sizeof(_audiostream)-8)
					{
						GUI_Alert("Maformed header!");
						return 0;
					}		
					printf("Trying to continue anyway\n");			
				}
				fread(&_audiostream,sizeof(_audiostream),1,_fd);
#ifdef ADM_BIG_ENDIAN
				Endian_AviStreamHeader(&_audiostream);
#endif
				if(_audiostream.fccType!=MKFCC('a','u','d','s'))
				{	
					printf("Not an audio track!\n");
					return 0;
				}
				// now read extra stuff
				fseeko(_fd,_Tracks[audioTrack].strf.offset,SEEK_SET);		
				extra=_Tracks[audioTrack].strf.size-sizeof(_wavHeader);
				if(extra<0)
				{	
					printf("WavHeader is not big enough (%lu/%lu)!\n",
					_Tracks[audioTrack].strf.size,sizeof(WAVHeader));
					return 0;
				}
				fread(&_wavHeader,sizeof(WAVHeader),1,_fd);				
#ifdef ADM_BIG_ENDIAN
				Endian_WavHeader(&_wavHeader);
#endif
				if(extra>2)
				{				
					fgetc(_fd);fgetc(_fd);
					extra-=2;
					_audioExtraLen=extra;		
					_audioExtraData=new uint8_t [extra];
					fread(_audioExtraData,extra,1,_fd);
				}					
			
			}		
		}
		
		// now look at the index stuff
		// there could be 3 cases:
		// 1- It is a openDML index, meta index  + several smaller index
		// 2- It is a legacy index (type 1 , most common)
		// 3- It is a broken index or no index at all
		//
		// If it is a openDML index we will find a "indx" field in the Tracks
		// Else we will find it in _regularIndex Track
		// Since openDML often also have a regular index we will try open DML first
		
		uint8_t ret=0;
		Dump();
		
		// take the size of riff header and actual file size
		uint64_t riffSize;
		fseeko(_fd,0,SEEK_END);		
		_fileSize=ftello(_fd);
		fseeko(_fd,0,SEEK_SET);
		read32();
		riffSize=(uint64_t )read32();
				
		
		// 1st case, we have an avi < 4 Gb
		// potentially avi type 1		
		if((_fileSize<4*1024*1024*1024LL)&&
			// if riff size is ~ fileSize try regular index
			 (abs(riffSize-_fileSize)<1024*1024))
			{
				printf("Size looks good, maybe type 1 avi\n");
				if(!ret && !_Tracks[vidTrack].indx.offset) // try regular avi
					ret=indexRegular(vidTrack,audioTrack,audioTrackNumber);		
				if (!ret && _Tracks[vidTrack].indx.offset)	
					ret=indexODML(vidTrack,audioTrack,audioTrackNumber);
				if(!ret) // re-index!
					ret=indexReindex(vidTrack,audioTrack,audioTrackNumber);		
			} // else try openDML/reindexing
		else
			{
				printf("Size mismatch, not type 1 avi\n");
				if (!ret && _Tracks[vidTrack].indx.offset)	
					ret=indexODML(vidTrack,audioTrack,audioTrackNumber);
				if(!ret) // re-index!
					ret=indexReindex(vidTrack,audioTrack,audioTrackNumber);			
			
			}
				
		if(!ret) 
		{
			printf("Cound not index it properly...\n");
			return 0;
		
		}				
		if(!_audioIdx) _isaudiopresent=0;
		else
		{
			// build audio stream
		 	_audioTrack = new AVDMAviAudioStream(_audioIdx,
   						_nbAudioChunk,
						_fd,
						&_wavHeader,						
						0,
						_audioExtraLen,_audioExtraData);
		
		}
		_videostream.fccHandler=_video_bih.biCompression;
		printf("\nOpenDML file successfully read..\n");
		
		return ret;
	
}
/**
    \fn saveAsBmp
    \brief save current image into filename, into bmp format
*/
uint8_t  ADMImage::saveAsBmp(const char *filename)
{
  BITMAPFILEHEADER bmfh;
  BITMAPINFOHEADER bmph;
  FILE *fd;
  uint32_t sz;
  uint16_t s16;
  uint32_t s32;
  
  sz = _width* _height * 3;

  bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
  bmfh.bfOffBits = sizeof (bmfh) + sizeof (bmph);
//_________________________________________
  bmph.biSize = sizeof (bmph);
  bmph.biWidth = _width;
  bmph.biHeight = _height;
  bmph.biPlanes = 1;
  bmph.biBitCount = 24;
  bmph.biCompression = 0;	// COMPRESSION NONE
  bmph.biSizeImage = sz;
  bmph.biXPelsPerMeter = 0;
  bmph.biYPelsPerMeter = 0;
  bmph.biClrUsed = 0;
  bmph.biClrImportant = 0;
/*
	bmph.resolutionUnits=0;
	bmph.origin=0;
	bmph.colorEncoding=0;
*/

  ADMImage image(_width,_height);
  

  printf ("\n %u x %u=%u\n", bmph.biWidth, bmph.biHeight, sz);

  uint8_t *out;

        out=(uint8_t *)ADM_alloc(sz);
        if(!out)
        {
            GUI_Error_HIG(QT_TR_NOOP("Memory error"), NULL);
//            ADM_dealloc(out);
            return 0;
        }

        if(!COL_yv12rgbBMP(bmph.biWidth, bmph.biHeight,data, out))
        {
              GUI_Error_HIG(QT_TR_NOOP("Error converting to BMP"), NULL);
              ADM_dealloc(out);
              return 0;
        }
        fd = fopen (filename, "wb");
        if (!fd)
        {
                GUI_Error_HIG (QT_TR_NOOP("Something bad happened"), NULL);
                ADM_dealloc(out);
                return 0;
        }

	// Bitmpap file header, not using tructure due to gcc padding it
#ifdef ADM_BIG_ENDIAN
	s16 = 0x424D;
#else	
  	s16 = 0x4D42;
#endif	
  	s32 = 14 + sizeof (bmph) + sz;
#ifdef ADM_BIG_ENDIAN	
	#define SWAP32(x) x=R32(x)	
#else
	#define SWAP32(x) ; 
#endif
        SWAP32(s32);	
        fwrite (&s16, 2, 1, fd);
        fwrite (&s32, 4, 1, fd);
        s32 = 0;
        fwrite (&s32, 4, 1, fd);
        s32 = 14 + sizeof (bmph);
        SWAP32(s32);
        fwrite (&s32, 4, 1, fd);
#ifdef ADM_BIG_ENDIAN
	Endian_BitMapInfo(&bmph);
#endif
        fwrite (&bmph, sizeof (bmph), 1, fd);
        fwrite (out, sz, 1, fd);
  
        fclose(fd);
        ADM_dealloc(out);
        return 1;
}
/**
    \fn saveAsBmp
    \brief save current image into filename, into bmp format
*/
bool  ADMImage::saveAsBmp(const char *filename)
{
  ADM_BITMAPFILEHEADER bmfh;
  ADM_BITMAPINFOHEADER bmph;
  FILE *fd;
  uint32_t sz;
  uint16_t s16;
  uint32_t s32;

  sz = _width* _height * 3;

  bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
  bmfh.bfOffBits = sizeof (bmfh) + sizeof (bmph);
//_________________________________________
  bmph.biSize = sizeof (bmph);
  bmph.biWidth = _width;
  bmph.biHeight = _height;
  bmph.biPlanes = 1;
  bmph.biBitCount = 24;
  bmph.biCompression = 0;	// COMPRESSION NONE
  bmph.biSizeImage = sz;
  bmph.biXPelsPerMeter = 0;
  bmph.biYPelsPerMeter = 0;
  bmph.biClrUsed = 0;
  bmph.biClrImportant = 0;
/*
	bmph.resolutionUnits=0;
	bmph.origin=0;
	bmph.colorEncoding=0;
*/

  ADMImageDefault image(_width,_height);


  printf ("\n %u x %u=%u\n", bmph.biWidth, bmph.biHeight, sz);

  uint8_t *out;

        out=(uint8_t *)ADM_alloc(sz);
        if(!out)
        {
            GUI_Error_HIG(QT_TR_NOOP("Memory error"), NULL);
//            ADM_dealloc(out);
            return 0;
        }
        ADMColorScalerSimple converter(bmph.biWidth, bmph.biHeight, ADM_COLOR_YV12,ADM_COLOR_RGB24);
        converter.convertImage(this,out);
        uint32_t ww=bmph.biWidth;
        uint32_t hh=bmph.biHeight;
        uint8_t *swap = new uint8_t[ww*3];
        uint8_t *up=out;
        uint8_t *down=out+(hh-1)*ww*3;
        
        for(int y=0;y<hh>>1;y++)
        {
            SwapMe(swap,up,ww); 
            SwapMe(up,down,ww);
            memcpy( down,swap,ww*3);
            down-=3*ww;
            up+=3*ww;
        }

		delete [] swap;

        fd = ADM_fopen (filename, "wb");
        if (!fd)
        {
                GUI_Error_HIG (QT_TR_NOOP("Something bad happened"), NULL);
                ADM_dealloc(out);
                return 0;
        }

	// Bitmpap file header, not using tructure due to gcc padding it
#ifdef ADM_BIG_ENDIAN
	s16 = 0x424D;
#else
  	s16 = 0x4D42;
#endif
  	s32 = 14 + sizeof (bmph) + sz;
#ifdef ADM_BIG_ENDIAN
	#define SWAP32(x) x=R32(x)
#else
	#define SWAP32(x) ;
#endif
        SWAP32(s32);
        fwrite (&s16, 2, 1, fd);
        fwrite (&s32, 4, 1, fd);
        s32 = 0;
        fwrite (&s32, 4, 1, fd);
        s32 = 14 + sizeof (bmph);
        SWAP32(s32);
        fwrite (&s32, 4, 1, fd);
#ifdef ADM_BIG_ENDIAN
	Endian_BitMapInfo(&bmph);
#endif
        fwrite (&bmph, sizeof (bmph), 1, fd);
        fwrite (out, sz, 1, fd);

        fclose(fd);
        ADM_dealloc(out);
        return 1;
}
uint8_t asfHeader::loadVideo(asfChunk *s)
{
  uint32_t w,h,x;
            printf("--\n");
            w=s->read32();
            h=s->read32();
            s->read8();
            x=s->read16();
            _isvideopresent=1;

            memset(&_mainaviheader,0,sizeof(_mainaviheader));
            _mainaviheader.dwWidth=w;
            _mainaviheader.dwHeight=h;
            _video_bih.biWidth=w;
            _video_bih.biHeight=h;
            printf("Pic Width  %04d\n",w);
            printf("Pic Height %04d\n",h);
            printf(" BMP size  %04d (%04d)\n",x,(int)sizeof(ADM_BITMAPINFOHEADER));
            s->read((uint8_t *)&_video_bih,sizeof(ADM_BITMAPINFOHEADER));

		#ifdef ADM_BIG_ENDIAN
			Endian_BitMapInfo(&_video_bih);
		#endif


            _videostream.fccHandler=_video_bih.biCompression;
            printf("Codec : <%s> (%04x)\n",
                    fourCC::tostring(_video_bih.biCompression),_video_bih.biCompression);
            if(fourCC::check(_video_bih.biCompression,(uint8_t *)"DVR "))
            {
              // It is MS DVR, fail so that the mpeg2 indexer can take it from here
              _videostream.fccHandler=_video_bih.biCompression=fourCC::get((uint8_t *)"MPEG");
              printf("This is MSDVR, not ASF\n");
              return 0; 
            }
            printBih(&_video_bih);
#if 1
            if(_video_bih.biSize>sizeof(ADM_BITMAPINFOHEADER))
            {
                    x=_video_bih.biSize;
#else
            if(x>sizeof(ADM_BITMAPINFOHEADER))
            {
#endif
              _videoExtraLen=x-sizeof(ADM_BITMAPINFOHEADER);
              _videoExtraData=new uint8_t[_videoExtraLen];
              s->read(_videoExtraData,_videoExtraLen);
              ADM_info("We have %d bytes of extra data for video.\n",(int)_videoExtraLen);
            }else
            {
                ADM_info("No extra data for video\n");
            }
            uint64_t l=ftello(_fd);
            printf("Bytes left : %d\n",(int)(s->endPos()-l));
            return 1;
}
/**
    \fn      buildIndex
    \brief   Scan the file to build an index
    
    Header Chunk
            Chunk
            Chunk
            Chunk
            
    Data chunk
            Chunk
            Chunk
            
    We skip the 1st one, and just read the header of the 2nd one
    
*/
uint8_t asfHeader::buildIndex(void)
{
  uint32_t fSize;
  const chunky *id;
  uint32_t chunkFound;
  uint32_t r=5;
  uint32_t len;
  
  fseeko(_fd,0,SEEK_END);
  fSize=ftello(_fd);
  fseeko(_fd,0,SEEK_SET);
  
  asfChunk h(_fd);
  printf("[ASF] ********** Building index **********\n");
  printf("[ASF] Searching data\n");
  while(r--)
  {
    h.nextChunk();    // Skip headers
    id=h.chunkId();
    h.dump();
    if(id->id==ADM_CHUNK_DATA_CHUNK) break;
    h.skipChunk();
  }
  if(id->id!=ADM_CHUNK_DATA_CHUNK) return 0;
  // Remove leftover from DATA_chunk
 // Unknown	GUID	16
//       Number of packets	UINT64	8
//       Unknown	UINT8	1
//       Unknown	UINT8	1
//   
  h.read32();
  h.read32();
  h.read32();
  h.read32();
  _nbPackets=(uint32_t) h.read64();
  h.read16();
  
  len=h.chunkLen-16-8-2-24;
  
  printf("[ASF] nbPacket  : %u\n",_nbPackets);
  printf("[ASF] len to go : %u\n",len);
  printf("[ASF] scanning data\n");
  _dataStartOffset=ftello(_fd);
  
  // Here we go
  asfPacket *aPacket=new asfPacket(_fd,_nbPackets,_packetSize,
                                   &readQueue,&storageQueue,_dataStartOffset);
  uint32_t packet=0;
#define MAXIMAGE (_nbPackets)
  uint32_t sequence=0;
  uint32_t ceilImage=MAXIMAGE;

  nbImage=0;
  
  len=0;
  asfIndex indexEntry;
  memset(&indexEntry,0,sizeof(indexEntry));
  bool first=true;
  DIA_workingBase *progressBar=createWorking("Indexing");
  uint32_t fileSizeMB=(uint32_t)(fSize>>10);

  uint64_t lastDts[ASF_MAX_AUDIO_TRACK];
  for(int i=0;i<ASF_MAX_AUDIO_TRACK;i++)
  {
        lastDts[i]=0;
  }


  while(packet<_nbPackets)
  {
    while(readQueue.size())
    {
      asfBit *bit=NULL;

      // update UI
      uint32_t curPos=(uint32_t)(ftello(_fd)>>10);
      progressBar->update(curPos,fileSizeMB);

      bit=readQueue.front();
      readQueue.pop_front();

      // --
      uint64_t dts=bit->dts;
      uint64_t pts=bit->pts;
        aprintf("** DTS=%s\n",ADM_us2plain(dts));
        aprintf("** PDTS=%s\n",ADM_us2plain(pts));
      if(bit->stream==_videoStreamId)
      {
          aprintf(">found video packet of size=%d off=%d seq %d, while curseq =%d, dts=%s",
                        bit->len,bit->offset,  bit->sequence,curSeq, ADM_us2plain(dts));
          aprintf(" pts=%s\n",ADM_us2plain(pts));
          if(bit->sequence!=sequence || first==true)
          {
            if(first==false)
            {
                indexEntry.frameLen=len;
                aprintf("Pushing video frame index=%d seq=%d pts=%s \n",
                        _index.size(),
                        indexEntry.segNb,ADM_us2plain(indexEntry.pts));
                aprintf("dts=%s\n",ADM_us2plain(indexEntry.dts));
                _index.append(indexEntry);
            }
            
            aprintf("New sequence\n");
            if( ((sequence+1)&0xff)!=(bit->sequence&0xff))
            {
                ADM_warning("!!!!!!!!!!!! non continuous sequence %u %u\n",sequence,bit->sequence); 
            }
            
            
            indexEntry.frameLen=0;
            indexEntry.segNb=bit->sequence;
            indexEntry.packetNb=bit->packet;
            indexEntry.flags=bit->flags;
            indexEntry.dts=dts;
            indexEntry.pts=pts;
            if(first==false)
            {
                sequence=bit->sequence;
                readQueue.push_front(bit); // reuse it next time
                len=0;
                continue;

            }else
            {
                sequence=bit->sequence;
                first=false; // first packet
            }
            
          }
          len+=bit->len;
      } // End of video stream Id
      else  // Audio ?
      {
        int found=0;
        for(int i=0;i<_nbAudioTrack && !found;i++)
        {
          if(bit->stream == _allAudioTracks[i].streamIndex)
          {
            if(bit->pts!=ADM_NO_PTS)
            {
                if(!lastDts[i] || (bit->pts>lastDts[i]+500000L)) // seek point every 500 ms
                {
                    asfAudioSeekPoint seek;
                        seek.pts=bit->pts;
                        seek.packetNb=bit->packet;
                        (audioSeekPoints[i]).append(seek);
      
#if 1
                        if(!lastDts[i])
                            printf("Adding seek point for track %d at %s (packet=%d)\n",
                            i,ADM_us2plain(bit->pts),(int)seek.packetNb);
#endif
                        lastDts[i]=bit->pts;
                        aprintf("Adding seek point for track %d at %s (packet=%d)\n",
                            i,ADM_us2plain(bit->pts),(int)seek.packetNb);
                }
            }
            found=1;
          }
        }
        if(!found) 
        {
          printf("Unmapped stream %u\n",bit->stream); 
        }
      }
      delete [] bit->data;
      bit->data=NULL;
      storageQueue.push_back(bit);
    }
    //working->update(packet,_nbPackets);

    packet++;
    aPacket->nextPacket(0xff); // All packets
    aPacket->skipPacket();
  }
  delete progressBar;
  delete aPacket;
  //delete working;
  /* Compact index */
  
  fseeko(_fd,_dataStartOffset,SEEK_SET);
  printf("[ASF] %u images found\n",nbImage);
  printf("[ASF] ******** End of buildindex *******\n");

  nbImage=_index.size();;
  if(!nbImage) return 0;
  
  uint64_t shift=60*1000*1000;
  bool canShift=false;
  uint64_t tPts;
  tPts=_index[0].pts;
    ADM_info("First image pts: %s, dts: %s\n",ADM_us2plain(tPts), ADM_us2plain(_index[0].dts));
   if(tPts != ADM_NO_PTS)
    {
        shift=tPts;
        ADM_info("Video shift = %s\n",ADM_us2plain(tPts));
        canShift=true;
    }else
        canShift=false;
    for(int i=0;i<_nbAudioTrack;i++)
    {
        if(!audioSeekPoints[i].size())
        {
            ADM_info("audio track : %d, no seek\n",i);
            canShift=false;
            continue;
        }
        tPts=audioSeekPoints[i][0].pts;
        ADM_info("audio track : %d, %s\n",i,ADM_us2plain(tPts));
        if(tPts<shift) shift=tPts;
    }
    if(canShift)
    {
            ADM_info("Shifting a/v raw=%s\n",ADM_us2plain(shift));
    }else
    {
            ADM_info("Can t shift\n");
            shift=0;
    }
  _videostream.dwLength=_mainaviheader.dwTotalFrames=nbImage;
  
  _index[0].flags=AVI_KEY_FRAME;
  if(_index[0].pts==ADM_NO_PTS) _index[0].pts=_index[0].dts;
  // Update fps
  // In fact it is an average fps
  //
    _videostream.dwScale=1000;
    // check if we have a duration per frame for video...
    int n=frameDurationMapping.size();
    int dex=-1;
    for(int i=0;i<n;i++)
    {
        if(frameDurationMapping[i].streamNb==_videoStreamId)
            dex=i;
    }
    if(dex!=-1)
    {
        ADM_info("Average fps provided\n");
        setFps(frameDurationMapping[dex].usPerFrame);
    }
    else
    {
      ADM_info("Fps not provided, guessing it from nbFrame and duration\n");
      uint32_t avgFps;
      if(_index[nbImage-1].pts!=ADM_NO_PTS && _index[0].pts!=ADM_NO_PTS)
      {
          float f=(_index[nbImage-1].pts-_index[0].pts);
            f/=nbImage; // average duration of 1 image in us
            setFps((uint64_t) f);
      }else
        {
            printf("[Asf] No pts, setting 30 fps hardcoded\n");
            _videostream.dwRate=(uint32_t)30000;;
        }
    }
    if(shift)
    {
        double frames3=_videostream.dwScale;
                frames3/=_videostream.dwRate;
                frames3*=3*1000*1000; // 
            ADM_info("3 frames time = %s\n",ADM_us2plain((uint64_t)frames3));
        uint64_t frame64=(uint64_t)frames3;
        if(frame64<shift) shift=shift-frame64;
        else shift=0;

        shiftAudioVideoBy(shift);
    }
    return 1;
  
}