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