1 /***************************************************************************
2     \file ADM_flv.cpp
3     \author (C) 2007 by mean    email                : fixounet@free.fr
4 
5 
6 Not sure if the timestamp is PTS or DTS (...)
7 
8       See lavformat/flv[dec/env].c for detail
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19 
20 #include "ADM_default.h"
21 #include "fourcc.h"
22 #include "DIA_coreToolkit.h"
23 #include "ADM_aacinfo.h"
24 #include "ADM_flv.h"
25 
26 #include <math.h>
27 #include <algorithm>
28 #include <vector>
29 #if 0
30     #define aprintf printf
31 #else
32     #define aprintf(...) {}
33 #endif
34 // Borrowed from lavformt/flv.h
35 #include "libavformat/flv.h"
36 #include "libavutil/intfloat.h"
37 // Borrowed from lavformt/flv.h
38 uint32_t ADM_UsecFromFps1000(uint32_t fps1000);
39 
40 #ifdef USE_BUFFERED_IO
Skip(uint32_t len)41 uint8_t flvHeader::Skip(uint32_t len)
42 {
43     return parser->forward(len);
44 }
read(uint32_t len,uint8_t * where)45 uint8_t flvHeader::read(uint32_t len, uint8_t *where)
46 {
47     if(len==parser->read32(len,where))
48         return 1;
49     return 0;
50 }
read8(void)51 uint8_t flvHeader::read8(void)
52 {
53     return parser->read8i();
54 }
read16(void)55 uint32_t flvHeader::read16(void)
56 {
57     uint32_t r=parser->read16i();
58     return r;
59 }
read24(void)60 uint32_t flvHeader::read24(void)
61 {
62     uint32_t r=parser->read16i();
63     return (r<<8)+(uint32_t)parser->read8i();
64 }
read32(void)65 uint32_t flvHeader::read32(void)
66 {
67     return parser->read32i();
68 }
69 #else
70 /**
71     \fn Skip
72     \brief Skip some bytes from the file
73 */
Skip(uint32_t len)74 uint8_t flvHeader::Skip(uint32_t len)
75 {
76   fseeko(_fd,len,SEEK_CUR);
77   return 1;
78 }
79 /**
80     \fn read
81     \brief read the given size from file
82 */
83 
read(uint32_t len,uint8_t * where)84 uint8_t flvHeader::read(uint32_t len, uint8_t *where)
85 {
86 
87     uint32_t got=fread(where,1,len,_fd);
88     if(len!=got)
89     {
90       printf("[FLV] Read error : asked %u, got %u\n",len,got);
91       return 0;
92     }
93     return 1;
94 }
95 //__________________________________________________________
read8(void)96 uint8_t flvHeader::read8(void)
97 {
98   uint8_t r;
99     aprintf("[Read]At 0x%x ",ftello(_fd));
100     fread(&r,1,1,_fd);
101     aprintf("uint8_t =%d ",r);
102     return r;
103 }
read16(void)104 uint32_t flvHeader::read16(void)
105 {
106   uint8_t r[2];
107     aprintf("[Read]At 0x%x ",ftello(_fd));
108     fread(r,2,1,_fd);
109     aprintf("uint16_t =%d ",(r[0]<<8)+r[1]);
110     return (r[0]<<8)+r[1];
111 }
read24(void)112 uint32_t flvHeader::read24(void)
113 {
114   uint8_t r[3];
115     aprintf("[Read]At 0x%x ",ftello(_fd));
116     fread(r,3,1,_fd);
117     aprintf("uint24_t =%d ",(r[0]<<16)+(r[1]<<8)+r[2]);
118     return (r[0]<<16)+(r[1]<<8)+r[2];
119 }
read32(void)120 uint32_t flvHeader::read32(void)
121 {
122   uint8_t r[4];
123     aprintf("[Read]At 0x%x ",ftello(_fd));
124     fread(r,4,1,_fd);
125     aprintf("uint32_t =%d ",(r[0]<<24)+(r[1]<<16)+(r[2]<<8)+r[3]);
126     return (r[0]<<24)+(r[1]<<16)+(r[2]<<8)+r[3];
127 }
128 #endif
129 /**
130     \fn     readFlvString
131     \brief  read pascal like string
132 */
133 #define FLV_MAX_STRING 255
readFlvString(void)134 char *flvHeader::readFlvString(void)
135 {
136 static uint8_t stringz[FLV_MAX_STRING+1];
137     int size=read16();
138     if(size>FLV_MAX_STRING)
139     {
140         int pre=FLV_MAX_STRING;
141         read(pre,stringz);
142         ADM_warning("String way too large :%d\n",size);
143         mixDump(stringz,pre);
144         stringz[0]='X';
145         stringz[1]='X';
146         stringz[2]=0;
147         stringz[FLV_MAX_STRING]=0;
148         Skip(size-FLV_MAX_STRING);
149         return (char *)stringz;
150     }
151     read(size,stringz);
152     stringz[size]=0;
153     return (char *)stringz;
154 }
155 
timeBaseFromFps1000(uint32_t v,uint32_t * num,uint32_t * den)156 static bool timeBaseFromFps1000(uint32_t v, uint32_t *num, uint32_t *den)
157 {
158     if(!v || !num || !den)
159         return false;
160     switch(v)
161     {
162         case 23976:
163             *num=1001;
164             *den=24000;
165             break;
166         case 29970:
167             *num=1001;
168             *den=30000;
169             break;
170         case 59940:
171             *num=1001;
172             *den=60000;
173             break;
174         default:
175             *num=1000;
176             *den=v;
177             break;
178     }
179     return true;
180 }
181 
182 /**
183     \fn setProperties
184     \brief get a couple key/value and use it if needed...
185 */
setProperties(const char * name,float value)186 void flvHeader::setProperties(const char *name,float value)
187 {
188     if(!strcmp(name,"framerate"))
189     {
190         value*=1000.;
191         value+=0.49;
192         uint32_t v=(uint32_t)value;
193         uint32_t num,den;
194         if(timeBaseFromFps1000(v,&num,&den))
195         {
196             _videostream.dwScale=num;
197             _videostream.dwRate=den;
198             _mainaviheader.dwMicroSecPerFrame=0; // conformance with constant fps will be probed later
199         }
200         return;
201     }
202     if(!strcmp(name,"width"))
203     {
204         metaWidth=(uint32_t)value;
205     }
206     if(!strcmp(name,"height"))
207     {
208         metaHeight=(uint32_t)value;
209     }
210     if(!strcmp(name,"frameWidth"))
211     {
212         metaFrameWidth=(uint32_t)value;
213     }
214     if(!strcmp(name,"frameHeight"))
215     {
216         metaFrameHeight=(uint32_t)value;
217     }
218 
219 }
220 #define Nest() {for(int xxx=0;xxx<nesting;xxx++) printf("\t");}
221 /**
222     \fn parseOneMeta
223 */
parseOneMeta(const char * stri,uint64_t endPos,bool & end)224 bool flvHeader::parseOneMeta(const char *stri,uint64_t endPos,bool &end)
225 {
226     static int nesting=0;
227     nesting++;
228     int type=read8();
229     Nest();
230     printf("\n>> type :%d ",type);
231 #ifdef USE_BUFFERED_IO
232     uint64_t pos=0;
233     parser->getpos(&pos);
234     aprintf("nesting = %d, at %d, : ,end=%d",nesting,pos,endPos);
235     switch(type)
236     {
237         case AMF_DATA_TYPE_NULL:
238             parser->setpos(endPos);
239             break;
240         case AMF_DATA_TYPE_OBJECT_END:
241             Nest(); printf("** Object end**.\n");
242             parser->getpos(&pos);
243             if(pos>=endPos-4)
244                 parser->setpos(endPos);
245             end=true;
246             nesting--;
247             break;
248         case AMF_DATA_TYPE_OBJECT:
249         {
250             printf("\n");
251             bool myEnd=false;
252             parser->getpos(&pos);
253             while(pos<endPos-4 && myEnd==false)
254             {
255                 Nest();
256                 parser->getpos(&pos);
257                 aprintf("Pos = %d, end=%d (object)\n",pos,endPos-4);
258                 char *o=readFlvString();
259                 Nest(); printf("\t ** Object**:%s",o);
260                 if(false==parseOneMeta(o,endPos,myEnd)) return false;
261 /*
262                 char objType=read8();
263                 printf("-->%d",objType);
264                 if(objType!=10)
265                 {
266                     ADM_warning("type is not strict array\n");
267                     goto xxer;
268                 }
269                 int count=read32();
270                 printf(", count=%d\n",count);
271                 for(int i=0;i<count;i++)
272                 {
273                     if(false==parseOneMeta(endPos)) return false;
274                 }
275                 break;
276 */
277                 parser->getpos(&pos);
278             }
279             break;
280         }
281         case AMF_DATA_TYPE_ARRAY:
282         {
283             uint32_t len=read32();
284             Nest();printf("\n**[FLV] Array : %" PRIu32" entries**\n",len);
285             bool theend;
286             parser->getpos(&pos);
287             for(int i=0;i<len && pos<endPos-4;i++)
288                 if(false==parseOneMeta("",endPos,theend)) return false;
289             Nest();printf("\n");
290             break;
291         }
292         case AMF_DATA_TYPE_DATE: Skip(8+2);break;
293         case AMF_DATA_TYPE_NUMBER:
294         {
295             float val;
296             uint64_t hi,lo;
297             hi=read32();lo=read32();
298             hi=(hi<<32)+lo;
299             val=(float)av_int2double(hi);
300             printf("->%f",val);
301             setProperties(stri,val);
302             break;
303         }
304         case AMF_DATA_TYPE_STRING:
305         {
306             int r=read16();
307 #if 1
308             Nest();printf("<");
309             for(int i=0;i<r;i++)
310             {
311                 printf("%c",read8());
312             }
313             printf(">");
314 #else
315             Skip(r);
316 #endif
317         }
318             break;
319         case AMF_DATA_TYPE_BOOL: read8();break;
320         case AMF_DATA_TYPE_MIXEDARRAY:
321         {
322             read32();
323             parser->getpos(&pos);
324             while(pos<endPos-4)
325             {
326                 char *o=readFlvString();
327                 bool theend;
328                 if(!o) break;
329                 Nest();printf("** MixedArray:%s **",o);
330                 if(false==parseOneMeta(o,endPos,theend)) return false;
331                 parser->getpos(&pos);
332             }
333             if(read8()!=AMF_END_OF_OBJECT) return false;
334          }
335              break;
336         default: printf("Unknown type=%d\n",type);ADM_assert(0);
337     }
338     printf("\n");
339 
340     nesting--;
341     return true;
342 #else
343             aprintf("nesting = %d, at %d, : ,end=%d",nesting,ftello(_fd),endPos);
344             switch(type)
345             {
346                 case AMF_DATA_TYPE_NULL:
347                                 fseek(_fd,endPos,SEEK_SET);
348                                 break;
349                 case AMF_DATA_TYPE_OBJECT_END:
350                                 Nest(); printf("** Object end**.\n");
351                                 if(ftello(_fd)>=endPos-4)
352                                 {
353                                     fseek(_fd,endPos,SEEK_SET);
354                                 }
355                                 end=true;
356                                 nesting--;
357                                 break;
358                 case AMF_DATA_TYPE_OBJECT:
359                 {
360                         printf("\n");
361                         bool myEnd=false;
362                         while(ftello(_fd)<endPos-4 && myEnd==false)
363                         {
364                                 Nest();aprintf("Pos = %d, end=%d (object)\n",ftello(_fd),endPos-4);
365                                 char *o=readFlvString();
366                                Nest(); printf("\t ** Object**:%s",o);
367                                 if(false==parseOneMeta(o,endPos,myEnd)) return false;
368 /*
369                                 char objType=read8();
370                                 printf("-->%d",objType);
371                                 if(objType!=10)
372                                 {
373                                         ADM_warning("type is not strict array\n");
374                                         goto xxer;
375                                 }
376                                 int count=read32();
377                                 printf(", count=%d\n",count);
378                                 for(int i=0;i<count;i++)
379                                 {
380                                         if(false==parseOneMeta(endPos)) return false;
381                                 }
382                                 break;
383 */
384 
385                         }
386                         break;
387 
388                 }
389                 case AMF_DATA_TYPE_ARRAY:
390                                     {
391                                             uint32_t len=read32();
392                                             Nest();printf("\n**[FLV] Array : %" PRIu32" entries**\n",len);
393                                             bool theend;
394                                             for(int i=0;i<len && ftello(_fd)<endPos-4;i++)
395                                                 if(false==parseOneMeta("",endPos,theend)) return false;
396                                             Nest();printf("\n");
397                                             break;
398                                     }
399                 case AMF_DATA_TYPE_DATE: Skip(8+2);break;
400                 case AMF_DATA_TYPE_NUMBER:
401                                         {
402                                             float val;
403                                             uint64_t hi,lo;
404                                             hi=read32();lo=read32();
405                                             hi=(hi<<32)+lo;
406                                             val=(float)av_int2double(hi);
407                                             printf("->%f",val);
408                                             setProperties(stri,val);
409                                         }
410                                         ;break;
411                 case AMF_DATA_TYPE_STRING:
412                                                 {
413                                                 int r=read16();
414 
415 
416                                                 #if 1
417                                                     Nest();printf("<");
418                                                     for(int i=0;i<r;i++)
419                                                     {
420                                                         printf("%c",read8());
421                                                     }
422                                                     printf(">");
423                                                 #else
424                                                     Skip(r);
425                                                 #endif
426                                                 }
427 
428                                                 break;
429                 case AMF_DATA_TYPE_BOOL: read8();break;
430                 case AMF_DATA_TYPE_MIXEDARRAY:
431                                             {
432                                                 read32();
433                                                  while(ftello(_fd)<endPos-4)
434                                                 {
435                                                             char *o=readFlvString();
436                                                             bool theend;
437                                                             if(!o) break;
438                                                             Nest();printf("** MixedArray:%s **",o);
439                                                             if(false==parseOneMeta(o,endPos,theend)) return false;
440 
441                                                 }
442                                                 if(read8()!=AMF_END_OF_OBJECT) return false;
443 
444                                              }
445                                             break;
446                 default : printf("Unknown type=%d\n",type);ADM_assert(0);
447             }
448             printf("\n");
449 
450             nesting--;
451             return true;
452 #endif
453 xxer:
454     nesting --;
455     return false;
456 }
457 /**
458     \fn parseMetaData
459     \brief
460 */
parseMetaData(uint32_t remaining)461 uint8_t flvHeader::parseMetaData(uint32_t remaining)
462 {
463 #ifdef USE_BUFFERED_IO
464     uint64_t pos=0;
465     parser->getpos(&pos);
466     pos+=remaining;
467     ADM_assert(!(pos&0xffffffff00000000));
468     uint32_t endPos=pos;
469 #else
470     uint32_t endPos=ftello(_fd)+remaining;
471 #endif
472     // Check the first one is onMetaData...
473     uint8_t type=read8();
474     char *z;
475     if(type!=AMF_DATA_TYPE_STRING) // String!
476         goto endit;
477     z=readFlvString();
478     printf("[FlashString] %s\n",z);
479     if(z && strncmp(z,"onMetaData",10)) goto endit;
480     // Normally the next one is mixed array
481 #ifdef USE_BUFFERED_IO
482     parser->getpos(&pos);
483     while(pos<endPos-4)
484     {
485         bool theend;
486         printf("\n----------------------- Parse---------------------\n");
487         if(false==parseOneMeta("meta",endPos,theend)) goto endit;
488         parser->getpos(&pos);
489     }
490 
491 #else
492     while(ftello(_fd)<endPos-4)
493     {
494         bool theend;
495         printf("\n----------------------- Parse---------------------\n");
496         if(false==parseOneMeta("meta",endPos,theend)) goto endit;
497     }
498 #endif
499 endit:
500 #ifdef USE_BUFFERED_IO
501     parser->setpos(endPos);
502 #else
503     fseeko(_fd,endPos,SEEK_SET);
504 #endif
505     updateDimensionWithMeta(videoCodec);
506     return 1;
507 }
508 /**
509     \fn searchMinimum
510     \brief returns minimum time in us between 2 video frames
511 
512 */
searchMinimum(void)513 uint32_t flvHeader::searchMinimum(void)
514 {
515     uint32_t delta=0xF000000;
516     for(int i=0;i<videoTrack->_nbIndex-1;i++)
517     {
518         flvIndex *x=&(videoTrack->_index[i]);
519         if((x[1].dtsUs-x[0].dtsUs)<delta) delta=x[1].dtsUs-x[0].dtsUs;
520 
521     }
522     return delta;
523 }
524 /**
525     \fn extraHeader
526     \brief if returns true means we must skip the remainder
527 */
extraHeader(flvTrak * trk,uint32_t * remain,bool have_cts,int32_t * cts)528 bool flvHeader::extraHeader(flvTrak *trk,uint32_t *remain,bool have_cts,int32_t *cts)
529 {
530     int type=read8();
531     int r=*remain;
532     r--;
533     if(have_cts)
534     {
535         uint32_t c=read24();
536          *cts=(c+0xff800000)^0xff800000;
537         //printf("Type :%d\n",type);
538         r-=3;
539     }
540     if(!type)
541     {  // Grab extra data
542         if(trk->extraData)
543         {
544             Skip(r);
545             r=0;
546         }
547         else
548         {
549             ADM_info("[FLV] found some extradata %" PRIu32"\n",r);
550             trk->extraData=new uint8_t[r];
551             trk->extraDataLen=r;
552             read(r,trk->extraData);
553             mixDump(trk->extraData,r);
554             r=0;
555         }
556         *remain=r;
557         return true;
558     }
559     *remain=r;
560     return false;
561 }
562 /**
563       \fn open
564       \brief open the flv file, gather infos and build index(es).
565 */
566 
open(const char * name)567 uint8_t flvHeader::open(const char *name)
568 {
569   uint32_t prevLen, type, size, dts;
570   uint64_t pos=0;
571   bool firstVideo=true;
572   bool tryProbedAvgFps=false;
573   int32_t firstCts=0;
574   _isvideopresent=0;
575   _isaudiopresent=0;
576   audioTrack=NULL;
577   videoTrack=NULL;
578   _videostream.dwRate=0;
579   _videostream.dwScale=1000;
580   _filename=ADM_strdup(name);
581 #ifdef USE_BUFFERED_IO
582   parser=new fileParser(CACHE_SIZE);
583   ADM_assert(parser);
584   int append=0;
585   if(!parser->open(name,&append))
586   {
587     ADM_error("[flv] Cannot open %s\n",name);
588     return 0;
589   }
590   uint64_t fileSize=parser->getSize();
591 #else
592   _fd=ADM_fopen(name,"rb");
593   if(!_fd)
594   {
595     printf("[FLV] Cannot open %s\n",name);
596     return 0;
597   }
598   // Get size
599   uint64_t fileSize=0;
600   fseeko(_fd,0,SEEK_END);
601   fileSize=ftello(_fd);
602   fseeko(_fd,0,SEEK_SET);
603   printf("[FLV] file size :%" PRIu64 " bytes\n",fileSize);
604 #endif
605   // It must begin by F L V 01
606   uint8_t four[4];
607 
608   read(4,four);
609   if(four[0]!='F' || four[1]!='L' || four[2]!='V')
610   {
611      printf("[FLV] Not a flv file %s\n",name);
612     return 0;
613   }
614   // Next one is flags
615   uint32_t flags=read8();
616   if(flags & 1) // VIDEO
617   {
618     _isvideopresent=1;
619     printf("[FLV] Video flag\n");
620   }else
621     {
622     GUI_Info_HIG(ADM_LOG_INFO,QT_TRANSLATE_NOOP("flvdemuxer","Warning"),QT_TRANSLATE_NOOP("flvdemuxer","This FLV file says it has no video.\nI will assume it has and try to continue"));
623     _isvideopresent=1;
624     }
625   if(flags & 4) // Audio
626   {
627     _isaudiopresent=1;
628     printf("[FLV] Audio flag\n");
629   }
630 
631 
632   // Skip header
633   uint32_t skip=read32();
634 #ifdef USE_BUFFERED_IO
635   parser->setpos(skip);
636   printf("[flv] Skipping %u header bytes\n",skip);
637   parser->getpos(&pos);
638 #else
639   fseeko(_fd,skip,SEEK_SET);
640   printf("[FLV] Skipping %u header bytes\n",skip);
641   pos=ftello(_fd);
642 #endif
643   printf("pos:%" PRIu64 "/%" PRIu64 "\n",pos,fileSize);
644   // Create our video index
645   videoTrack=new flvTrak(50);
646   if(_isaudiopresent)
647     audioTrack=new flvTrak(50);
648   else
649     audioTrack=NULL;
650   // Loop
651   while(pos<fileSize-14)
652   {
653     int32_t cts=0;
654     uint32_t pts=0xffffffff;
655 #ifdef USE_BUFFERED_IO
656     parser->getpos(&pos);
657 #else
658     pos=ftello(_fd);
659 #endif
660     prevLen=read32();
661     type=read8();
662     size=read24();
663     dts=read24();
664     dts|=((uint32_t)read8())<<24;
665     read24(); // StreamID, always 0
666     aprintf("--------\n");
667     aprintf("prevLen=%d\n",(int)prevLen);
668     aprintf("type  =%d\n",(int)type);
669     aprintf("size  =%d\n",(int)size);
670     aprintf("dts   =%d\n",(int)dts);
671     if(!size)
672     {
673 #ifdef USE_BUFFERED_IO
674         parser->getpos(&pos);
675 #endif
676         continue;
677     }
678     uint32_t remaining=size;
679     //printf("[FLV] At %08" PRIu64 " found type %x size %u pts%u\n",pos,type,size,dts);
680     switch(type)
681     {
682       case FLV_TAG_TYPE_AUDIO:
683           {
684             aprintf("** Audio **\n");
685             if(!_isaudiopresent)
686             {
687                 audioTrack=new flvTrak(50);
688                 _isaudiopresent=1; /* Damn  lying headers...*/
689             };
690             uint8_t flags=read8();
691             int of=1+4+3+3+1+4;
692             remaining--;
693             int format=flags>>4;
694             int fq=(flags>>2)&3;
695             int bps=(flags>>1) & 1;
696             int channel=(flags) & 1;
697             if(!audioTrack->_nbIndex) // first frame..
698             {
699                setAudioHeader(format,fq,bps,channel);
700             }
701             if(format==10)
702             {
703                 if(extraHeader(audioTrack,&remaining,false,&cts)) continue;
704             }
705 #ifdef USE_BUFFERED_IO
706             if(remaining)
707             {
708                 parser->getpos(&pos);
709                 insertAudio(pos,remaining,dts);
710             }
711 #else
712             if(remaining)
713                 insertAudio(ftello(_fd),remaining,dts);
714 #endif
715           }
716           break;
717       case FLV_TAG_TYPE_META:
718                 aprintf("** Meta **\n");
719                 parseMetaData(remaining);
720                 remaining=0;
721                 break;
722       case FLV_TAG_TYPE_VIDEO:
723           {
724             int of=1+4+3+3+1+4;
725             aprintf("** Video **\n");
726             uint8_t flags=read8();
727             remaining--;
728             int frameType=flags>>4;
729 
730             videoCodec=(flags)&0xf;
731 
732             if(videoCodec==FLV_CODECID_VP6 || videoCodec==FLV_CODECID_VP6A)
733             {
734               read8(); // 1 byte of extraData
735               remaining--;
736               of++;
737             }
738 
739             if(firstVideo==true) // first frame..
740             {
741                 if(!setVideoHeader(videoCodec,&remaining)) return 0;
742                 firstVideo=false;
743             }
744             if(videoCodec==FLV_CODECID_H264)
745             {
746                 if(true==extraHeader(videoTrack,&remaining,true,&cts))
747                 {
748                     ADM_info("Retrieving H.264 info...\n");
749                     nalsize=ADM_getNalSizeH264(videoTrack->extraData,videoTrack->extraDataLen);
750                     spsinfo=new ADM_SPSInfo;
751                     if(false==extractSPSInfo_mp4Header(videoTrack->extraData,videoTrack->extraDataLen,spsinfo))
752                     {
753                         ADM_warning("Cannot decode SPS\n");
754                         delete spsinfo;
755                         spsinfo=NULL;
756                     }
757                     continue;
758                 }
759                 if(!videoTrack->_nbIndex) firstCts=cts;
760                 if(!bFramesPresent && firstCts!=cts)
761                     bFramesPresent=true;
762                 int64_t sum=cts+dts;
763                 if(sum<0) pts=0xffffffff;
764                     else pts=dts+(int32_t)cts;
765 
766             }
767 #ifdef USE_BUFFERED_IO
768             if(remaining)
769             {
770                 bool check=bFramesPresent;
771                 parser->getpos(&pos);
772                 insertVideo(pos,remaining,frameType,dts,pts);
773                 if(!ptsInvalid && bFramesPresent!=check)
774                 {
775                     ADM_warning("Invalid PTS detected at frame %d\n",(int)videoTrack->_nbIndex-1);
776                     ptsInvalid=true;
777                 }
778                 pos+=remaining;
779                 remaining=0;
780                 parser->setpos(pos);
781             }
782 #else
783             if(remaining)
784             {
785                 bool check=bFramesPresent;
786                 pos=ftello(_fd);
787                 insertVideo(pos,remaining,frameType,dts,pts);
788                 if(!ptsInvalid && bFramesPresent!=check)
789                 {
790                     ADM_warning("Invalid PTS detected at frame %d\n",(int)videoTrack->_nbIndex-1);
791                     ptsInvalid=true;
792                 }
793                 pos+=remaining;
794                 remaining=0;
795                 fseeko(_fd,pos,SEEK_SET);
796             }
797 #endif
798           }
799            break;
800       default: printf("[FLV]At 0x%" PRIx64 ", unhandled type %u\n",pos,type);
801     }
802     Skip(remaining);
803   } // while
804 
805   // Udpate frame count etc..
806   ADM_info("[FLV] Found %u frames\n",videoTrack->_nbIndex);
807 
808     if(videoCodec==FLV_CODECID_H264 && spsinfo && spsinfo->width && spsinfo->height)
809     {
810         ADM_info("Setting width and height to values obtained from codec\n");
811         ADM_info("W %d\n",spsinfo->width);
812         ADM_info("H %d\n",spsinfo->height);
813         metaWidth=spsinfo->width;
814         metaHeight=spsinfo->height;
815         updateDimensionWithMeta(FLV_CODECID_H264);
816     }
817 
818    _videostream.dwLength= _mainaviheader.dwTotalFrames=videoTrack->_nbIndex;
819 
820     // Can we force a constant frame rate based on metadata?
821     uint64_t delay=(firstCts>0)? 1000LL*firstCts : 0;
822     if(false==enforceConstantFps(_videostream.dwScale,_videostream.dwRate,delay,bFramesPresent))
823     {
824         ADM_info("Cannot force constant frame rate for timebase %u / %u\n",_videostream.dwScale,_videostream.dwRate);
825         tryProbedAvgFps=true;
826     }
827    // Compute average fps
828     float f=_videostream.dwLength;
829     uint64_t duration=videoTrack->_index[videoTrack->_nbIndex-1].dtsUs;
830     duration+=(uint64_t)((double)duration/(double)f+0.49);
831 
832     if(duration)
833           f=1000.*1000.*1000.*f/duration;
834      else  f=25000;
835     // If it was available from the metadata, use the one from metadata
836     if(tryProbedAvgFps)
837     {
838         float d=searchMinimum();
839         printf("[FLV] minimum delta :%d\n",(uint32_t)d);
840         d=1/d;
841         d*=1000*1000*1000;
842 
843         uint32_t avg=(uint32_t)floor(f);
844         uint32_t max=(uint32_t)floor(d);
845         if(max<2) max=2; // 500 fps max
846         printf("[FLV] Avg fps :%d, max fps :%d\n",avg,max);
847         // Can we use the probed average fps for timebase?
848         bool skip=false;
849         uint32_t num,den;
850         if(timeBaseFromFps1000(avg,&num,&den))
851         {
852             skip = (num==_videostream.dwScale) && (den==_videostream.dwRate);
853             if(!skip)
854             {
855                 _videostream.dwScale=num;
856                 _videostream.dwRate=den;
857                 _mainaviheader.dwMicroSecPerFrame=0; // assume a perfectly regular stream
858             }
859         }
860         if(skip || false==enforceConstantFps(_videostream.dwScale,_videostream.dwRate,delay,bFramesPresent))
861         {
862             if(skip)
863                 ADM_info("Average fps matches metadata, skipping the check.\n");
864             else
865                 ADM_info("Cannot force CFR based on avg fps for timebase %u / %u\n",_videostream.dwScale,_videostream.dwRate);
866             // Can we use at least a timebase derived from max fps?
867             if(timeBaseFromFps1000(max,&num,&den))
868             {
869                 _videostream.dwScale=num;
870                 _videostream.dwRate=den;
871             }
872             _mainaviheader.dwMicroSecPerFrame=ADM_UsecFromFps1000(avg); // should be safe now
873             if(false==checkTimeBase(_videostream.dwScale,_videostream.dwRate))
874             {
875                 ADM_info("Cannot use timebase %u / %u from max fps, falling back to 1 / 1000 equivalent.\n",_videostream.dwScale,_videostream.dwRate);
876                 {
877                     _videostream.dwRate=16000; // lavf doesn't like low clocks like e.g. 1000 // FIXME
878                     _videostream.dwScale=16;
879                 }
880             }
881         }
882     }
883 
884     ADM_info("[FLV] Duration: %" PRIu64" ms, time base: %u / %u\n",duration/1000,
885         _videostream.dwScale,_videostream.dwRate);
886 
887    //
888     _videostream.fccType=fourCC::get((uint8_t *)"vids");
889     _video_bih.biBitCount=24;
890     _videostream.dwInitialFrames= 0;
891     _videostream.dwStart= 0;
892     videoTrack->_index[0].flags &= ~AVI_B_FRAME;
893     videoTrack->_index[0].flags |= AVI_KEY_FRAME;
894 
895     // if it is AAC and we have extradata...
896     if(_isaudiopresent && wavHeader.encoding && audioTrack->extraDataLen>=2)
897     {
898         AacAudioInfo info;
899         // Check frequency..
900         if(ADM_getAacInfoFromConfig(audioTrack->extraDataLen,audioTrack->extraData,info))
901         {
902             ADM_info("AAC detected with fq=%d, sbr=%d\n",info.frequency,info.sbr);
903             wavHeader.frequency=info.frequency;
904         }
905     }
906 
907     // audio track
908     if(_isaudiopresent)
909     {
910         _access=new ADM_flvAccess(name,audioTrack);
911         _audioStream=ADM_audioCreateStream(&wavHeader,_access);
912     }
913     else
914     {
915         _audioStream = NULL;
916        _access=NULL;
917     }
918 #ifdef USE_BUFFERED_IO
919     // Too big cache may be detrimental for keyframe-based navigation, reduce cache size
920     parser->setBufferSize(DMX_BUFFER);
921 #endif
922   printf("[FLV]FLV successfully read\n");
923 
924   return 1;
925 }
926 /**
927         \fn getVideoDuration
928         \brief Returns duration of video in us
929 */
getVideoDuration(void)930 uint64_t flvHeader::getVideoDuration(void)
931 {
932     uint64_t pts=videoTrack->_index[videoTrack->_nbIndex-1].ptsUs;
933     if(pts==ADM_NO_PTS) pts=videoTrack->_index[videoTrack->_nbIndex-1].dtsUs;
934     pts+=frameToUs(1);
935     return pts;
936 }
937 
938 /**
939       \fn setVideoHeader
940       \brief Set codec and stuff
941 */
updateDimensionWithMeta(uint32_t codec)942 bool flvHeader::updateDimensionWithMeta(uint32_t codec)
943 {
944     if(codec==0xFFFF) return false;
945     ADM_info("We got metadata : %d x %d\n",(int)metaWidth,(int)metaHeight,(int)codec);
946     if(metaFrameWidth)  metaWidth=metaFrameWidth;
947     if(metaFrameHeight) metaHeight=metaFrameHeight;
948     if( metaWidth && metaHeight )
949     {
950         switch(codec)
951         {
952             case FLV_CODECID_VP6A:
953             case FLV_CODECID_H264:
954             case FLV_CODECID_VP6:
955 
956                     _video_bih.biHeight=_mainaviheader.dwHeight=metaHeight ;
957                     _video_bih.biWidth=_mainaviheader.dwWidth=metaWidth;
958                     break;
959             default:break;
960         }
961     }
962     return true;
963 }
964 /**
965     \fn setVideoHeader
966 */
setVideoHeader(uint8_t codec,uint32_t * remaining)967 uint8_t flvHeader::setVideoHeader(uint8_t codec,uint32_t *remaining)
968 {
969     printf("[FLV] Video Codec:%u\n",codec);
970 
971     _video_bih.biWidth=_mainaviheader.dwWidth=320;
972     _video_bih.biHeight=_mainaviheader.dwHeight=240;
973 #define MKFLV(x,t) case FLV_CODECID_##x :  _videostream.fccHandler=_video_bih.biCompression=\
974                             fourCC::get((uint8_t *)#t);break;
975     switch(codec)
976     {
977         MKFLV(H264,H264);
978         MKFLV(H263,FLV1);
979         MKFLV(VP6,VP6F);
980         MKFLV(VP6A,VP6A);
981         default : _videostream.fccHandler=_video_bih.biCompression=fourCC::get((uint8_t *)"XXX");break;
982     }
983     updateDimensionWithMeta(codec);
984 
985     if(codec==FLV_CODECID_H263 && *remaining)
986     {
987 #ifdef USE_BUFFERED_IO
988       uint64_t pos=0;
989       parser->getpos(&pos);
990 #else
991       uint32_t pos=ftello(_fd);
992 #endif
993       uint32_t len=*remaining,width,height;
994       uint8_t *buffer=new uint8_t[len];
995       read(len,buffer);
996 #ifdef USE_BUFFERED_IO
997       parser->setpos(pos);
998 #else
999       fseeko(_fd,pos,SEEK_SET);
1000 #endif
1001        /* Decode header, from h263dec.c / lavcodec*/
1002       if(extractH263FLVInfo(buffer,len,&width,&height))
1003       {
1004          _video_bih.biHeight=_mainaviheader.dwHeight=height;
1005          _video_bih.biWidth=_mainaviheader.dwWidth=width;
1006       }
1007       delete [] buffer;
1008     }
1009    return 1;
1010 }
1011 /**
1012       \fn setAudioHeader
1013       \brief Build WavHeader from info
1014 
1015 */
setAudioHeader(uint32_t format,uint32_t fq,uint32_t bps,uint32_t channels)1016 uint8_t   flvHeader::setAudioHeader(uint32_t format,uint32_t fq,uint32_t bps,uint32_t channels)
1017 {
1018   switch(fq)
1019   {
1020     case 3: wavHeader.frequency=44100;break;
1021     case 2: wavHeader.frequency=22050;break;
1022     case 1: wavHeader.frequency=11025;break;
1023     case 0:
1024           if(format==5) wavHeader.frequency=8000;
1025           else wavHeader.frequency=5512;
1026           break;
1027     default: printf("[FLV]Unknown frequency:%u\n",fq);
1028   }
1029   switch(format)
1030   {
1031     case 6: wavHeader.encoding=WAV_NELLYMOSER;break;
1032     case 2: wavHeader.encoding=WAV_MP3;break;
1033     case 3: wavHeader.encoding=WAV_PCM;break;
1034     case 0: wavHeader.encoding=WAV_LPCM;break;
1035     case 1: wavHeader.encoding=WAV_MSADPCM;break;
1036     case 10:wavHeader.encoding=WAV_AAC;break;
1037     default:
1038           printf("[FLV]Unsupported audio codec:%u\n",format);
1039   }
1040   switch(channels)
1041   {
1042     case 1: wavHeader.channels=2;break;
1043     case 0: wavHeader.channels=1;break;
1044         default:
1045           printf("[FLV]Unsupported channel mode :%u\n",channels);
1046   }
1047   switch(bps)
1048   {
1049     case 1: wavHeader.bitspersample=16;break;
1050     case 0: wavHeader.bitspersample=8;break;
1051         default:
1052           printf("[FLV]Unsupported bps mode :%u\n",bps);
1053   }
1054   wavHeader.byterate=(64000)/8; // 64 kbits default
1055   return 1;
1056 }
1057 /**
1058       \fn insertVideo
1059       \brief add a frame to the index, grow the index if needed
1060 */
insertVideo(uint64_t pos,uint32_t size,uint32_t frameType,uint32_t dts,uint32_t pts)1061 uint8_t flvHeader::insertVideo(uint64_t pos,uint32_t size,uint32_t frameType,uint32_t dts,uint32_t pts)
1062 {
1063     videoTrack->grow();
1064     flvIndex *x=&(videoTrack->_index[videoTrack->_nbIndex]);
1065     x->size=size;
1066     x->pos=pos;
1067     x->dtsUs=dts*1000LL;
1068     if(pts==0xffffffff) x->ptsUs=ADM_NO_PTS;
1069         else
1070       x->ptsUs=pts*1000LL;
1071     if(videoCodec==FLV_CODECID_H264 && nalsize && spsinfo)
1072     {
1073         uint8_t *buffer=new uint8_t[size];
1074         if(read(size,buffer))
1075         { // Keep fingers crossed that we don't encounter inband SPS changing midstream.
1076             uint32_t flags=0;
1077             if(extractH264FrameType(buffer,size,nalsize,&flags,NULL,spsinfo))
1078             {
1079                 if(!!(flags & AVI_KEY_FRAME) != (frameType==1))
1080                     ADM_warning("Container and codec disagree about frame %u: %s says keyframe.\n",
1081                         videoTrack->_nbIndex,(flags & AVI_KEY_FRAME)? "codec" : "container");
1082                 if(flags & AVI_B_FRAME)
1083                     bFramesPresent=true;
1084                 x->flags=flags;
1085                 videoTrack->_nbIndex++;
1086                 return 1;
1087             }
1088         }
1089     }
1090     if(frameType==1)
1091     {
1092         x->flags=AVI_KEY_FRAME;
1093     }
1094     else
1095     {
1096           x->flags=0;
1097     }
1098     videoTrack->_nbIndex++;
1099     return 1;
1100 }
1101 /**
1102       \fn enforceConstantFps
1103       \brief Check whether we can force CFR and update video index if necessary
1104 */
enforceConstantFps(uint32_t scale,uint32_t rate,uint64_t delay,bool reorder)1105 bool flvHeader::enforceConstantFps(uint32_t scale, uint32_t rate, uint64_t delay, bool reorder)
1106 {
1107     if(!_videostream.dwRate)
1108         return false;
1109 
1110     double d=_videostream.dwScale;
1111     d*=1000.*1000;
1112     d/=_videostream.dwRate*2;
1113     d+=0.49;
1114     const int64_t threshold=(int64_t)d; // half of frame increment, as generous as possible
1115     const uint32_t nbFrames=videoTrack->_nbIndex;
1116     uint32_t i;
1117 
1118     for(i=0; i<nbFrames; i++)
1119     {
1120         d=i;
1121         d*=_videostream.dwScale;
1122         d*=1000.;
1123         d/=_videostream.dwRate;
1124         d*=1000.;
1125         d+=0.49;
1126         uint64_t expected=(uint64_t)d;
1127         flvIndex *x=&(videoTrack->_index[i]);
1128         if(x->dtsUs!=ADM_NO_PTS)
1129         {
1130             int64_t delta=x->dtsUs-expected;
1131             //printf("Frame %u dts delta: %" PRId64" us\n",i,delta);
1132             if(delta>threshold || -delta>threshold)
1133             {
1134                 ADM_warning("Delta %" PRId64" for frame %u exceeds threshold.\n",delta,i);
1135                 return false;
1136             }
1137         }
1138     }
1139     ADM_info("Forcing constant frame rate...\n");
1140     // Force constant frame rate
1141     for(i=0; i<nbFrames; i++)
1142     {
1143         d=i;
1144         d*=_videostream.dwScale;
1145         d*=1000.*1000;
1146         d/=_videostream.dwRate;
1147         d+=0.49;
1148         videoTrack->_index[i].dtsUs=(uint64_t)d;
1149     }
1150     // round up delay to a multiple of timebase
1151     if(delay)
1152     {
1153         uint64_t num=_videostream.dwScale;
1154         delay+=num-1;
1155         delay/=num;
1156         delay*=num;
1157     }
1158     if(reorder)
1159     {
1160         uint32_t i;
1161         std::vector <uint32_t> DisplayOrder;
1162         std::vector <uint64_t> sortedPts;
1163         for(i=0; i<nbFrames; i++)
1164         {
1165             flvIndex *x=&(videoTrack->_index[i]);
1166             if(x->ptsUs==ADM_NO_PTS) continue;
1167             sortedPts.push_back(x->ptsUs);
1168         }
1169         std::sort(sortedPts.begin(),sortedPts.end());
1170         for(i=0; i<nbFrames; i++)
1171         {
1172             uint32_t nbInvalid=0;
1173             flvIndex *x=&(videoTrack->_index[i]);
1174             if(x->ptsUs==ADM_NO_PTS)
1175             {
1176                 DisplayOrder.push_back(i);
1177                 nbInvalid++;
1178                 continue;
1179             }
1180             uint32_t base=0;
1181             if(i>32) base=i-32; // max 16 ref * 2 fields
1182             for(uint32_t j=base;j<sortedPts.size();j++)
1183             {
1184                 if(x->ptsUs!=sortedPts.at(j))
1185                     continue;
1186                 uint32_t k=nbInvalid+j;
1187                 ADM_assert(k<nbFrames);
1188                 DisplayOrder.push_back(k);
1189                 //printf("%u --> %u\n",i,k);
1190                 break;
1191             }
1192         }
1193         for(i=0; i<nbFrames; i++)
1194         {
1195             if(i+1>=DisplayOrder.size())
1196                 break;
1197             uint32_t j=DisplayOrder.at(i);
1198             flvIndex *x=&(videoTrack->_index[i]);
1199             if(x->ptsUs==ADM_NO_PTS) continue;
1200             x->ptsUs=videoTrack->_index[j].dtsUs+delay;
1201         }
1202     }else
1203     {
1204         for(i=0; i<nbFrames; i++)
1205         {
1206             flvIndex *x=&(videoTrack->_index[i]);
1207             x->ptsUs=x->dtsUs+delay;
1208         }
1209     }
1210     // verify that the delay is sufficient
1211     uint64_t delay2=0;
1212     for(i=0; i<nbFrames; i++)
1213     {
1214         flvIndex *x=&(videoTrack->_index[i]);
1215         if(x->ptsUs==ADM_NO_PTS || x->dtsUs==ADM_NO_PTS)
1216             continue;
1217         if(x->ptsUs+delay2<x->dtsUs)
1218             delay2+=x->dtsUs-x->ptsUs;
1219     }
1220     if(delay2)
1221     {
1222         ADM_warning("Original PTS delay is insufficient, adding %" PRIu64" us.\n",delay2);
1223         for(i=0; i<nbFrames; i++)
1224             videoTrack->_index[i].ptsUs+=delay2;
1225     }
1226     return true;
1227 }
1228 
1229 /**
1230       \fn checkTimeBase
1231       \brief Check whether all dts and pts can be expressed in the given timebase
1232 */
checkTimeBase(uint32_t scale,uint32_t rate)1233 bool flvHeader::checkTimeBase(uint32_t scale, uint32_t rate)
1234 {
1235     if(!scale || rate<1000)
1236         return false;
1237 
1238     uint32_t i;
1239     const uint32_t nbFrames=videoTrack->_nbIndex;
1240     scale*=1000;
1241     // check dts first
1242     for(i=0; i<nbFrames; i++)
1243     {
1244         flvIndex *x=&(videoTrack->_index[i]);
1245         if(x->dtsUs==ADM_NO_PTS || x->dtsUs<1000)
1246             continue;
1247         uint64_t low=x->dtsUs-1000; // -1 ms
1248         uint64_t high=x->dtsUs+1000; // +1 ms
1249         double f=low;
1250         f*=rate;
1251         f/=scale;
1252         f+=0.49;
1253         low=(uint64_t)f; // 1000 * scaled time
1254         f=high;
1255         f*=rate;
1256         f/=scale;
1257         f+=0.49;
1258         high=(uint64_t)f;
1259         if(high%1000>100 || low%1000<900)
1260         {
1261             ADM_warning("Frame %d dts is not a multiple of timebase.\n",i);
1262             return false;
1263         }
1264     }
1265     // now get pts delay
1266 #define HIGH_POINT 0xFFFFFFF0 // an arbitrary high value
1267     uint64_t delay=HIGH_POINT;
1268     for(i=0; i<nbFrames; i++)
1269     {
1270         flvIndex *x=&(videoTrack->_index[i]);
1271         if(x->ptsUs==ADM_NO_PTS)
1272             continue;
1273         if(x->ptsUs<delay) delay=x->ptsUs;
1274         if(!delay) break;
1275     }
1276     if(delay==HIGH_POINT)
1277         return true; // no valid pts
1278     ADM_info("Probed PTS delay: %" PRIu64" us.\n",delay);
1279     // check pts
1280     for(i=0; i<nbFrames; i++)
1281     {
1282         flvIndex *x=&(videoTrack->_index[i]);
1283         if(x->ptsUs==ADM_NO_PTS || x->ptsUs-delay<1000)
1284             continue;
1285         uint64_t low=x->ptsUs-delay-1000; // -1 ms
1286         uint64_t high=x->ptsUs-delay+1000; // +1 ms
1287         double f=low;
1288         f*=rate;
1289         f/=scale;
1290         f+=0.49;
1291         low=(uint64_t)f; // 1000 * scaled time
1292         f=high;
1293         f*=rate;
1294         f/=scale;
1295         f+=0.49;
1296         high=(uint64_t)f;
1297         if(high%1000>100 || low%1000<900)
1298         {
1299             ADM_warning("Frame %d pts is not a multiple of timebase.\n",i);
1300             return false;
1301         }
1302     }
1303     return true;
1304 }
1305 
1306 /**
1307       \fn insertAudio
1308       \brief add a frame to the index, grow the index if needed
1309 */
insertAudio(uint64_t pos,uint32_t size,uint32_t pts)1310 uint8_t flvHeader::insertAudio(uint64_t pos,uint32_t size,uint32_t pts)
1311 {
1312     audioTrack->grow();
1313     flvIndex *x=&(audioTrack->_index[audioTrack->_nbIndex]);
1314     x->size=size;
1315     x->pos=pos;
1316     x->dtsUs=pts*1000LL;
1317     x->flags=0;
1318     audioTrack->_nbIndex++;
1319     return 1;
1320 }
1321 
1322 
1323 
1324 /**
1325     \fn getAudioInfo
1326     \brief returns wav header for stream i (=0)
1327 */
getAudioInfo(uint32_t i)1328 WAVHeader *flvHeader::getAudioInfo(uint32_t i )
1329 {
1330   if(_isaudiopresent)
1331     return &wavHeader;
1332   else
1333       return NULL;
1334 }
1335 /**
1336    \fn getAudioStream
1337 */
1338 
getAudioStream(uint32_t i,ADM_audioStream ** audio)1339 uint8_t   flvHeader::getAudioStream(uint32_t i,ADM_audioStream  **audio)
1340 {
1341   if(_isaudiopresent)
1342   {
1343     *audio=_audioStream;
1344     return 1;
1345   }
1346   *audio=NULL;
1347   return 0;
1348 }
1349 /**
1350     \fn getNbAudioStreams
1351 
1352 */
getNbAudioStreams(void)1353 uint8_t   flvHeader::getNbAudioStreams(void)
1354 {
1355  if(_isaudiopresent)
1356   {
1357 
1358     return 1;
1359   }
1360   return 0;
1361 }
1362 /*
1363     __________________________________________________________
1364 */
1365 
Dump(void)1366 void flvHeader::Dump(void)
1367 {
1368 
1369 }
1370 /**
1371     \fn close
1372     \brief cleanup
1373 */
1374 
close(void)1375 uint8_t flvHeader::close(void)
1376 {
1377   if(_filename) ADM_dealloc(_filename);
1378   if(videoTrack)
1379   {
1380         if(videoTrack->extraData) delete [] videoTrack->extraData;
1381         delete videoTrack;
1382   }
1383   if(audioTrack)
1384   {
1385      if(audioTrack->extraData) delete [] audioTrack->extraData;
1386     delete audioTrack;
1387   }
1388 #ifdef USE_BUFFERED_IO
1389   if(parser)
1390   {
1391       delete parser;
1392       parser=NULL;
1393   }
1394 #else
1395   if(_fd) fclose(_fd);
1396   _fd=NULL;
1397 #endif
1398   if(_audioStream) delete _audioStream;
1399   if(_access) delete _access;
1400   if(spsinfo) delete spsinfo;
1401 
1402   _filename=NULL;
1403   videoTrack=NULL;
1404   audioTrack=NULL;
1405   _audioStream=NULL;
1406   _access=NULL;
1407   spsinfo=NULL;
1408   return 1;
1409 }
1410 /**
1411     \fn flvHeader
1412     \brief constructor
1413 */
1414 
flvHeader(void)1415  flvHeader::flvHeader( void ) : vidHeader()
1416 {
1417     videoCodec=0xFFFF;
1418 #ifdef USE_BUFFERED_IO
1419     parser=NULL;
1420 #else
1421     _fd=NULL;
1422 #endif
1423     _filename=NULL;
1424     videoTrack=NULL;
1425     audioTrack=NULL;
1426     _audioStream=NULL;
1427     _access=NULL;
1428     memset(&wavHeader,0,sizeof(wavHeader));
1429     metaWidth=0;
1430     metaHeight=0;
1431     metaFps1000=0;
1432     metaFrameWidth=0;
1433     metaFrameHeight=0;
1434     ptsInvalid=false;
1435     bFramesPresent=false;
1436     nalsize=0;
1437     spsinfo=NULL;
1438 }
1439 /**
1440     \fn flvHeader
1441     \brief destructor
1442 */
1443 
~flvHeader()1444  flvHeader::~flvHeader(  )
1445 {
1446   close();
1447 }
1448 
1449 
1450 /**
1451     \fn setFlag
1452     \brief Returns timestamp in us of frame "frame" (PTS)
1453 */
1454 
setFlag(uint32_t frame,uint32_t flags)1455   uint8_t  flvHeader::setFlag(uint32_t frame,uint32_t flags)
1456 {
1457     if(frame>=videoTrack->_nbIndex)
1458     {
1459         printf("[FLV] Setflags out of boud %u/%u\n",frame,videoTrack->_nbIndex);
1460         return 0;
1461     }
1462     videoTrack->_index[frame].flags=flags;
1463     return 1;
1464 }
1465 /**
1466     \fn getFlags
1467     \brief Returns timestamp in us of frame "frame" (PTS)
1468 */
1469 
getFlags(uint32_t frame,uint32_t * flags)1470 uint32_t flvHeader::getFlags(uint32_t frame,uint32_t *flags)
1471 {
1472     if(frame>=videoTrack->_nbIndex)
1473     {
1474         printf("[FLV] Getflags out of boud %u/%u\n",frame,videoTrack->_nbIndex);
1475         return 0;
1476     }
1477 
1478     *flags=videoTrack->_index[frame].flags;
1479     return  1;
1480 }
1481 
1482 /**
1483     \fn getTime
1484     \brief Returns timestamp in us of frame "frame" (PTS)
1485 */
getTime(uint32_t frame)1486 uint64_t flvHeader::getTime(uint32_t frame)
1487 {
1488      if(frame>=videoTrack->_nbIndex) return ADM_NO_PTS;
1489      flvIndex *idx=&(videoTrack->_index[frame]);
1490      return idx->ptsUs;
1491 }
1492 /**
1493         \fn getFrame
1494 */
1495 
getFrame(uint32_t frame,ADMCompressedImage * img)1496 uint8_t  flvHeader::getFrame(uint32_t frame,ADMCompressedImage *img)
1497 {
1498      if(frame>=videoTrack->_nbIndex) return 0;
1499      flvIndex *idx=&(videoTrack->_index[frame]);
1500 #ifdef USE_BUFFERED_IO
1501      parser->setpos(idx->pos);
1502      if(!read(idx->size,img->data))
1503          return 0;
1504 #else
1505      fseeko(_fd,idx->pos,SEEK_SET);
1506      fread(img->data,idx->size,1,_fd);
1507 #endif
1508      img->dataLength=idx->size;
1509      img->flags=idx->flags;
1510      //img->demuxerDts=ADM_COMPRESSED_NO_PTS;
1511     // For flash assume PTS=DTS (???)
1512      img->demuxerDts=idx->dtsUs;;
1513      img->demuxerPts=idx->ptsUs;;
1514      return 1;
1515 }
1516 /**
1517         \fn getExtraHeaderData
1518 */
getExtraHeaderData(uint32_t * len,uint8_t ** data)1519 uint8_t  flvHeader::getExtraHeaderData(uint32_t *len, uint8_t **data)
1520 {
1521         if(videoTrack)
1522         {
1523                 *len=videoTrack->extraDataLen;
1524                 *data=videoTrack->extraData;
1525                 return 1;
1526         }
1527         *len=0;
1528         *data=NULL;
1529         return 1;
1530 }
1531 
1532 /**
1533       \fn getFrameSize
1534       \brief return the size of frame frame
1535 */
getFrameSize(uint32_t frame,uint32_t * size)1536 uint8_t flvHeader::getFrameSize (uint32_t frame, uint32_t * size)
1537 {
1538    if(frame>=videoTrack->_nbIndex)
1539     {
1540         printf("[FLV] getFrameSize out of boud %u/%u\n",frame,videoTrack->_nbIndex);
1541         return 0;
1542     }
1543   *size = videoTrack->_index[frame].size;
1544   return 1;
1545 }
1546 //!!
1547 
1548 /**
1549     \fn getPtsDts
1550 */
getPtsDts(uint32_t frame,uint64_t * pts,uint64_t * dts)1551 bool    flvHeader::getPtsDts(uint32_t frame,uint64_t *pts,uint64_t *dts)
1552 {
1553 
1554     if(frame>=videoTrack->_nbIndex)
1555     {
1556       printf("[MKV] Frame %" PRIu32" exceeds # of frames %" PRIu32"\n",frame,videoTrack->_nbIndex);
1557       return 0;
1558     }
1559 
1560      flvIndex *idx=&(videoTrack->_index[frame]);
1561 
1562     *dts=idx->dtsUs; // FIXME
1563     *pts=idx->ptsUs;
1564     return true;
1565 }
1566 /**
1567         \fn setPtsDts
1568 */
setPtsDts(uint32_t frame,uint64_t pts,uint64_t dts)1569 bool    flvHeader::setPtsDts(uint32_t frame,uint64_t pts,uint64_t dts)
1570 {
1571     if(frame>=videoTrack->_nbIndex)
1572     {
1573       printf("[MKV] Frame %" PRIu32" exceeds # of frames %" PRIu32"\n",frame,videoTrack->_nbIndex);
1574       return 0;
1575     }
1576 
1577      flvIndex *idx=&(videoTrack->_index[frame]);
1578 
1579     idx->dtsUs=dts; // FIXME
1580     idx->ptsUs=pts;
1581     //*pts=idx->timeCodeUs; // FIXME PTS=DTS ??
1582     return true;
1583 }
1584 
1585 //EOF
1586