1 /***************************************************************************
2                         Mpeg2 in PS indexer
3 
4     VC1: /!\ Escaping not done (yet)
5 
6     copyright            : (C) 2005/2009 by mean
7     email                : fixounet@free.fr
8  ***************************************************************************/
9 
10 /***************************************************************************
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU General Public License as published by  *
14  *   the Free Software Foundation; either version 2 of the License, or     *
15  *   (at your option) any later version.                                   *
16  *                                                                         *
17  ***************************************************************************/
18 #include "ADM_tsIndex.h"
19 
20 static const uint32_t FPS[16]={
21                 0,                      // 0
22                 23976,          // 1 (23.976 fps) - FILM
23                 24000,          // 2 (24.000 fps)
24                 25000,          // 3 (25.000 fps) - PAL
25                 29970,          // 4 (29.970 fps) - NTSC
26                 30000,          // 5 (30.000 fps)
27                 50000,          // 6 (50.000 fps) - PAL noninterlaced
28                 59940,          // 7 (59.940 fps) - NTSC noninterlaced
29                 60000,          // 8 (60.000 fps)
30                 0,                      // 9
31                 0,                      // 10
32                 0,                      // 11
33                 0,                      // 12
34                 0,                      // 13
35                 0,                      // 14
36                 0                       // 15
37         };
38 
39 
40 /**
41       \fn TsIndexer
42       \brief main indexing loop for mpeg2 payload
43 */
tsIndexer(const char * file)44 uint8_t   tsIndexer(const char *file)
45 {
46     uint8_t r;
47     ADM_TS_TRACK *tracks;
48     uint32_t nbTracks;
49     listOfTsAudioTracks audioTrack;
50 
51     if(TS_scanForPrograms(file,&nbTracks,&tracks)==false)
52     {
53             printf("[Ts Indexer] Scan of pmt failed\n");
54             if(TS_guessContent(file,&nbTracks,&tracks)==false)
55             {
56                 printf("[Ts Indexer] Brute force scan failed\n");
57                 return 0;
58             }
59     }
60     ADM_assert(tracks);
61     ADM_assert(nbTracks);
62     //
63     // Now extract the datas from audio tracks & verify they are here
64     tsPacketLinear *p=new tsPacketLinear(0);
65     p->open(file,0);
66     for(int i=1;i<nbTracks;i++)
67     {
68         tsAudioTrackInfo trk;
69         trk.esId=tracks[i].trackPid;
70         trk.trackType=tracks[i].trackType;
71         trk.mux=ADM_TS_MUX_NONE;
72         trk.language=tracks[i].language;
73         if(true==tsGetAudioInfo(p,&trk))
74         {
75 
76               audioTrack.push_back(trk);
77         }
78     }
79     delete p;
80     printf("[TsIndexer] Audio probed, %d found, doing video\n",(int)audioTrack.size());
81     //
82     TsIndexerBase *dx=NULL;
83     switch(tracks[0].trackType)
84     {
85             case ADM_TS_MPEG2:
86                             dx=new TsIndexerMpeg2(&audioTrack);
87                             break;
88             case ADM_TS_VC1:
89                             dx=new TsIndexerVC1(&audioTrack);
90                             break;
91             case ADM_TS_H265:
92                             dx=new TsIndexerH265(&audioTrack);
93                             break;
94             case ADM_TS_H264:
95                             dx=new TsIndexerH264(&audioTrack);
96                             break;
97             default:
98                         r=0;
99                         break;
100     }
101     if(!dx)
102     {
103         ADM_warning("Unsupported video codec \n");
104         r=0;
105     }else
106     {
107         r=dx->run( file,&(tracks[0]));
108         delete dx;
109         dx=NULL;
110     }
111     delete [] tracks;
112     return r;
113 }
114 
115 /**
116     \fn TsIndexer
117 */
TsIndexerBase(listOfTsAudioTracks * trk)118 TsIndexerBase::TsIndexerBase(listOfTsAudioTracks *trk)
119 {
120 
121     index=NULL;
122     pkt=NULL;
123     audioTracks=NULL;
124     beginConsuming=0;
125     gui=NULL;
126     audioTracks=trk;
127     processedThisRound=0;
128 }
129 
130 /**
131     \fn ~TsIndexer
132 */
~TsIndexerBase()133 TsIndexerBase::~TsIndexerBase()
134 {
135     if(index) qfclose(index);
136     if(pkt) delete pkt;
137     if(gui) delete gui;
138     gui=NULL;
139 }
140 /**
141     \fn updateUI
142  *  \brief return false if abort is needed
143 */
updateUI(void)144 bool  TsIndexerBase::updateUI(void)
145 {
146     int p=++processedThisRound;
147         processedThisRound=0;
148         return !gui->update(p, pkt->getPos());
149 
150 }
151 /**
152     \fn writeVideo
153     \brief Write Video section of index file
154 */
writeVideo(TSVideo * video,ADM_TS_TRACK_TYPE trkType)155 bool TsIndexerBase::writeVideo(TSVideo *video,ADM_TS_TRACK_TYPE trkType)
156 {
157     qfprintf(index,"[Video]\n");
158     qfprintf(index,"Width=%d\n",video->w);
159     qfprintf(index,"Height=%d\n",video->h);
160     qfprintf(index,"Fps=%d\n",video->fps);
161     qfprintf(index,"Interlaced=%d\n",video->interlaced);
162     qfprintf(index,"AR=%d\n",video->ar);
163     qfprintf(index,"Pid=%d\n",video->pid);
164     if(video->extraDataLength)
165     {
166         qfprintf(index,"ExtraData=%d ",video->extraDataLength);
167         for(int i=0;i<video->extraDataLength;i++)
168             qfprintf(index," %02x",video->extraData[i]);
169         qfprintf(index,"\n");
170     }
171  switch(trkType)
172     {
173         case ADM_TS_MPEG2: qfprintf(index,"VideoCodec=Mpeg2\n");break;;
174         case ADM_TS_H264:  qfprintf(index,"VideoCodec=H264\n");break;
175         case ADM_TS_H265:  qfprintf(index,"VideoCodec=H265\n");break;
176         case ADM_TS_VC1:   qfprintf(index,"VideoCodec=VC1\n");break;
177         default: printf("[TsIndexer] Unsupported video codec\n");return false;
178 
179     }
180     return true;
181 }
182 /**
183     \fn writeSystem
184     \brief Write system part of index file
185 */
writeSystem(const char * filename,int append)186 bool TsIndexerBase::writeSystem(const char *filename,int append)
187 {
188     qfprintf(index,"PSD1\n");
189     qfprintf(index,"[System]\n");
190     qfprintf(index,"Version=%d\n",ADM_INDEX_FILE_VERSION);
191     qfprintf(index,"Type=T\n");
192     qfprintf(index,"File=%s\n",filename);
193     qfprintf(index,"Append=%u\n",(uint32_t)append);
194     return true;
195 }
196 /**
197     \fn     writeAudio
198     \brief  Write audio headers
199 */
writeAudio(void)200 bool TsIndexerBase::writeAudio(void)
201 {
202     if(!audioTracks) return false;
203     qfprintf(index,"[Audio]\n");
204     qfprintf(index,"Tracks=%d\n",audioTracks->size());
205     for(int i=0;i<audioTracks->size();i++)
206     {
207         char head[30];
208         tsAudioTrackInfo *t=&(*audioTracks)[i];
209         sprintf(head,"Track%1d",i);
210         qfprintf(index,"%s.pid=%x\n",head,t->esId);
211         qfprintf(index,"%s.codec=%d\n",head,t->wav.encoding);
212         qfprintf(index,"%s.fq=%d\n",head,t->wav.frequency);
213         qfprintf(index,"%s.chan=%d\n",head,t->wav.channels);
214         qfprintf(index,"%s.br=%d\n",head,t->wav.byterate);
215         qfprintf(index,"%s.muxing=%d\n",head,t->mux);
216         qfprintf(index,"%s.language=%s\n",head,t->language.c_str());
217         if(t->extraDataLen)
218         {
219             qfprintf(index,"%s.extraData=%d",head,t->extraDataLen);
220             uint8_t *p=t->extraData;
221             for(int i=0;i<t->extraDataLen;i++)
222                 qfprintf(index," %02x",p[i]);
223             qfprintf(index,"\n");
224         }
225     }
226     return true;
227 }
228 
229 
230 /**
231     \fn dumpUnits
232 */
dumpUnits(indexerData & data,uint64_t nextConsumed,const dmxPacketInfo * nextPacket)233 bool TsIndexerBase::dumpUnits(indexerData &data,uint64_t nextConsumed,const dmxPacketInfo *nextPacket)
234 {
235         // if it contain a SPS or a intra/idr, we start a new line
236         bool mustFlush=false;
237         bool picStructFromSei=false;
238         int n=listOfUnits.size();
239         int picIndex=0;
240         H264Unit *unit=&(listOfUnits[0]);
241         pictureStructure pictStruct=pictureFrame;
242 
243         // if I, IDR or SPS we start a new line
244         for(int i=0;i<n;i++)
245         {
246             switch(listOfUnits[i].unitType)
247             {
248                 case unitTypeSps: mustFlush=true; break;
249                 case unitTypePic:
250                             picIndex=i;
251                             if(!picStructFromSei)
252                                 pictStruct=listOfUnits[i].imageStructure;
253                             picStructFromSei=false;
254                             if(listOfUnits[i].imageType==1 || listOfUnits[i].imageType==4)
255                                 mustFlush=true;
256                             break;
257                 case unitTypeSei:
258                             pictStruct=listOfUnits[i].imageStructure;
259                             picStructFromSei=true;
260                             break;
261                 default:
262                         ADM_assert(0);
263                         break;
264             }
265         }
266         dmxPacketInfo *pic=&(listOfUnits[picIndex].packetInfo);
267         dmxPacketInfo *p=&(unit->packetInfo);
268         H264Unit      *picUnit=&(listOfUnits[picIndex]);
269         if(mustFlush)
270         {
271             if(audioTracks)
272             {
273                 qfprintf(index,"\nAudio bf:%08" PRIx64" ",nextPacket->startAt);
274                 packetTSStats *s;
275                 uint32_t na;
276                 pkt->getStats(&na,&s);
277                 ADM_assert(na==audioTracks->size());
278                 for(int i=0;i<na;i++)
279                 {
280                     packetTSStats *current=s+i;
281                     qfprintf(index,"Pes:%x:%08" PRIx64":%" PRIi32":%" PRId64" ",
282                                 current->pid,current->startAt,current->startSize,current->startDts);
283                 }
284             }
285             data.beginPts=pic->pts;
286             data.beginDts=pic->dts;
287             // start a new line
288             qfprintf(index,"\nVideo at:%08" PRIx64":%04" PRIx32" Pts:%08" PRId64":%08" PRId64" ",
289                         p->startAt,p->offset-unit->overRead,pic->pts,pic->dts);
290         }
291 
292 
293             int64_t deltaPts,deltaDts;
294 
295             if(data.beginPts==-1 || pic->pts==-1) deltaPts=-1;
296                 else deltaPts=pic->pts-data.beginPts;
297 
298             if(data.beginDts==-1 || pic->dts==-1) deltaDts=-1;
299                 else deltaDts=pic->dts-data.beginDts;
300 
301 
302         qfprintf(index," %c%c",Type[picUnit->imageType],Structure[pictStruct%6]);
303         int32_t delta=(int32_t)(nextConsumed-beginConsuming);
304 
305     //    printf("%d -- %d = %d\n",nextConsumed, beginConsuming,delta);
306 
307         qfprintf(index,":%06" PRIx32,delta);
308         qfprintf(index,":%" PRId64":%" PRId64,deltaPts,deltaDts);
309 
310         beginConsuming=nextConsumed;
311         listOfUnits.clear();
312         return true;
313 }
314 /**
315     \fn addUnit
316 */
addUnit(indexerData & data,int unitType2,const H264Unit & unit,uint32_t overRead)317 bool TsIndexerBase::addUnit(indexerData &data,int unitType2,const H264Unit &unit,uint32_t overRead)
318 {
319         H264Unit myUnit=unit;
320         myUnit.unitType=unitType2;
321         myUnit.overRead=overRead;
322 #if 0
323         printf("Adding new unit of type %x unitType2 PTS=%" PRId64" DTS=%" PRId64"\n",unitType2,
324                     unit.packetInfo.pts,
325                     unit.packetInfo.dts
326                     );
327 #endif
328         int n=listOfUnits.size();
329         if(n)
330             if(listOfUnits[n-1].unitType==unitTypePic)
331             {
332                 dumpUnits(data,myUnit.consumedSoFar-overRead,&(unit.packetInfo));
333                 if(!updateUI())
334                 {
335                     ADM_info("Indexer : cancelling\n");
336                     return false;
337                 }
338             }
339         listOfUnits.push_back(myUnit);
340         return true;
341 }
342 
updateLastUnitStructure(int t)343 bool    TsIndexerBase::updateLastUnitStructure(int t)
344 {
345     int n=listOfUnits.size();
346     if(!n)
347     {
348         ADM_error("Cannot update last pic, we have none.");
349         return false;
350     }
351     H264Unit &lastUnit=listOfUnits[n-1];
352     switch(t)
353     {
354         case 3 : lastUnit.imageStructure=pictureFrame;break;
355         case 1 : lastUnit.imageStructure=pictureFieldTop;break;
356         case 2 : lastUnit.imageStructure=pictureFieldBottom;break;
357         case 4 : lastUnit.imageStructure=pictureTopFirst;break;
358         case 5 : lastUnit.imageStructure=pictureBottomFirst;break;
359         default: ADM_warning("frame type %d met, this is illegal\n",t);break;
360     }
361     return true;
362 }
363 
364 /********************************************************************************************/
365 /********************************************************************************************/
366 /********************************************************************************************/
367 /********************************************************************************************/
368 
369 //
370 
371 //EOF
372