1 /*  dvbcut
2     Copyright (c) 2005 Sven Over <svenover@svenover.de>
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 
19 /* $Id$ */
20 
21 #include <cstdlib>
22 #include <cstring>
23 #include <stdint.h>
24 #include <cerrno>
25 #include <unistd.h>
26 #include <cmath>
27 
28 #include <list>
29 #include <utility>
30 #include <QCoreApplication>
31 
32 #include "port.h"
33 #include "mpgfile.h"
34 #include "tsfile.h"
35 #include "psfile.h"
36 #include "index.h"
37 #include "avframe.h"
38 #include "streamhandle.h"
39 #include "playaudio.h"
40 #include "muxer.h"
41 #include "logoutput.h"
42 
43 #include <stdio.h>
44 
45 const int mpgfile::frameratescr[16]=
46   {
47     1080000,1126125,1125000,1080000,900900,900000,540000,450450,450000,
48     1080000,1080000,1080000,1080000,1080000,1080000,1080000
49   };
50 
mpgfile(inbuffer & b,int initial_offset)51 mpgfile::mpgfile(inbuffer &b, int initial_offset)
52     : buf(b),
53     videostreams(0),audiostreams(0),
54     initialoffset(initial_offset),idx(*this),pictures(0),
55     time_base_num(1), time_base_den(25)
56 {}
57 
~mpgfile()58 mpgfile::~mpgfile()
59 {}
60 
61 /// Factory function
62 mpgfile*
open(inbuffer & b,std::string * errormessage)63 mpgfile::open(inbuffer &b, std::string *errormessage) {
64   if (errormessage)
65     errormessage->clear();
66 
67   if (b.providedata(64 << 10) < (64 << 10)) {
68     if (errormessage)
69       *errormessage = QCoreApplication::translate("mpgfile", "File too short").toStdString();
70     return 0;
71   }
72 
73   int initialoffset;
74   // 2011-04-24: check packet sizes from 188 up to 208. --mr
75   for (int stride = TSPACKETSIZE; stride <= MAXPACKETSIZE; stride += 4)
76     if ((initialoffset=tsfile::probe(b, stride))>=0) // is this an mpeg transport stream?
77       return new tsfile(b, initialoffset, stride);
78   if ((initialoffset=psfile::probe(b))>=0) // is this an mpeg program stream?
79     return new psfile(b, initialoffset);
80 
81   if (errormessage)
82     *errormessage = QCoreApplication::translate("mpgfile", "Unknown file type").toStdString();
83   return 0;
84 }
85 
decodegop(int start,int stop,std::list<avframe * > & framelist)86 void mpgfile::decodegop(int start, int stop, std::list<avframe*> &framelist)
87 {
88   stream *S=&s[videostream()];
89   if (!S->avcc)
90     return;
91 
92   if (start<0)
93     start=0;
94   if (stop<0)
95     stop=nextiframe(start+1)+1;
96   else if (stop<=start)
97     stop=start+1;
98   if (stop>pictures)
99     stop=pictures;
100 
101   if (stop<=start)
102     return;
103   int pic=lastseqheader(lastiframe(start));
104   int streampic=idx.indexnr(pic);
105   int seqnr=idx[streampic].getsequencenumber();
106 
107   streamhandle s(idx[streampic].getpos().packetposition());
108   streamdata *sd=s.newstream(VIDEOSTREAM,streamtype::mpeg2video,istransportstream());
109 
110   if (idx[streampic].getpos().packetoffset()>0)
111   {
112     while( sd->inbytes()<idx[streampic].getpos().packetoffset() )
113     {
114       if (streamreader(s)<=0)
115         return;
116     }
117     sd->discard(idx[streampic].getpos().packetoffset());
118   }
119 
120   if (int rv=avcodec_open2(S->avcc, S->dec, NULL))
121   {
122     fprintf(stderr,"avcodec_open returned %d\n",rv);
123     return;
124   }
125   avframe avf;
126   int last_cpn=-1;
127   bool firstframe=true, firstsequence=true;
128 
129   while (pic<stop && streampic<idx.getpictures())
130   {
131     filepos_t tp(getfilesize(),0);
132     if ((streampic+1)<idx.getpictures())
133       tp=idx[streampic+1].getpos();
134     while (sd->itemlist().empty() || s.fileposition<tp.fileposition())
135       if (streamreader(s)<=0)
136         break;
137 
138     int bytes=sd->inbytes();
139 
140     for(streamdata::itemlisttype::const_iterator it=sd->itemlist().begin();it!=sd->itemlist().end();++it)
141       if (it->fileposition.packetposition()==tp.packetposition())
142       {
143         bytes=it->bufferposition-sd->getoffset()+tp.packetoffset()-it->fileposition.packetoffset();
144         break;
145       }
146       else
147         if (it->fileposition.packetposition()>tp.packetposition())
148         {
149           bytes=it->bufferposition-sd->getoffset();
150           break;
151         }
152 
153     if (!firstframe && idx[streampic].getseqheader())
154       firstsequence=false;
155     firstframe=false;
156 
157     if (!firstsequence || idx[streampic].getsequencenumber()>=seqnr)
158     {
159       const uint8_t *data=(const uint8_t*)sd->getdata();
160       int frameFinished=0;
161 
162       int decodebytes=bytes;
163       while (decodebytes>0)
164       {
165         frameFinished=0;
166 
167         AVPacket pkt;
168         av_init_packet( &pkt );
169         pkt.data = (uint8_t*) data;
170         pkt.size = decodebytes;
171         int bytesDecoded=avcodec_decode_video2( S->avcc, avf,
172                                         &frameFinished, &pkt );
173 
174         if (bytesDecoded<0)
175         {
176           fprintf(stderr,"libavcodec error while decoding frame #%d\n",pic);
177           avcodec_close(S->avcc);
178           return;
179         }
180 
181         data+=bytesDecoded;
182         decodebytes-=bytesDecoded;
183 
184         if (frameFinished)
185         {
186           //fprintf(stderr, "* decoded frame %5d ilace:%d typ:%d pts=%f\n", pic, avf->interlaced_frame, avf->pict_type, (double)avf->pts/90000.0);
187           if (last_cpn!=avf->coded_picture_number)
188           {
189             last_cpn=avf->coded_picture_number;
190             if (pic>=start)
191               framelist.push_back(new avframe(avf,S->avcc));
192             ++pic;
193             if (pic>=stop)
194             {
195               frameFinished=0;
196               decodebytes=0;
197               break;
198             }
199           }
200           else
201             frameFinished=0;
202         }
203       }
204     }
205 
206     sd->discard(bytes);
207     ++streampic;
208   }
209 
210   if (pic < stop)
211   {
212     int frameFinished=0;
213 
214     AVPacket pkt;
215     av_init_packet( &pkt );
216     pkt.data = NULL;
217     pkt.size = 0;
218     avcodec_decode_video2( S->avcc, avf,
219                                         &frameFinished, &pkt );
220 
221     if (frameFinished)
222     {
223       if (last_cpn!=avf->coded_picture_number)
224       {
225         last_cpn=avf->coded_picture_number;
226         if (pic>=start)
227           framelist.push_back(new avframe(avf,S->avcc));
228       }
229     }
230   }
231 
232   time_base_num = S->avcc->time_base.num;
233   time_base_den = S->avcc->time_base.den;
234   if (S->avcc->ticks_per_frame > 0) {
235     //fprintf(stderr, "field rate -> frame rate\n");
236     time_base_num *= S->avcc->ticks_per_frame;
237   }
238 
239   avcodec_close(S->avcc);
240 }
241 
initaudiocodeccontext(int aud)242 void mpgfile::initaudiocodeccontext(int aud)
243 {
244   stream &S=s[audiostream(aud)];
245   S.infostring="Audio ";
246 
247   {
248     char number[16];
249     snprintf(number,16,"%d",aud);
250     S.infostring+=number;
251   }
252 
253   switch (S.type)
254   {
255   case streamtype::mpegaudio:
256     S.infostring+=" (MPEG)";
257     break;
258   case streamtype::ac3audio:
259     S.infostring+=" (AC3)";
260     break;
261   default:
262     S.infostring+=" (unknown)";
263     break;
264   }
265 }
266 
initcodeccontexts(int vid)267 void mpgfile::initcodeccontexts(int vid)
268 {
269   if (vid>=0) {
270     videostreams=1;
271     stream *S=&s[VIDEOSTREAM];
272     S->id=vid;
273     S->allocavcc();
274     S->avcc->codec_type=AVMEDIA_TYPE_VIDEO;
275     S->avcc->codec_id=AV_CODEC_ID_MPEG2VIDEO;
276     S->dec=avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
277     S->enc=avcodec_find_encoder(AV_CODEC_ID_MPEG2VIDEO);
278     S->type=streamtype::mpeg2video;
279     }
280 
281   for (int i=0;i<audiostreams;++i)
282     initaudiocodeccontext(i);
283 }
284 
285 #ifdef HAVE_LIB_AO
playaudio(int aud,int picture,int ms)286 void mpgfile::playaudio(int aud, int picture, int ms)
287 {
288   if (aud>=audiostreams || ms==0)
289     return;
290 
291   pts_t startpts=idx[idx.indexnr(picture)].getpts();
292   pts_t stoppts=startpts;
293 
294   if (ms<0)
295     startpts+=ms*90;
296   else
297     stoppts+=ms*90;
298 
299   int seekpic=idx.indexnr(picture);
300   while (seekpic>0 && idx[seekpic].getpts()>=startpts-180000)
301     --seekpic;
302   int stopreadpic=idx.indexnr(picture);
303   while (stopreadpic<pictures-1 && idx[stopreadpic].getpts()<stoppts+180000)
304     ++stopreadpic;
305   dvbcut_off_t stopreadpos=idx[stopreadpic].getpos().packetposition();
306 
307   streamhandle sh(idx[seekpic].getpos().packetposition());
308   streamdata *sd=sh.newstream(audiostream(aud),s[audiostream(aud)].type,istransportstream());
309 
310   while (sd->empty())
311   {
312     if (sh.fileposition > stopreadpos || streamreader(sh)<=0)
313       return; // data does not reach the point in time from which we like to start playing
314     while (!sd->empty() && !sd->itemlist().begin()->headerhaspts())
315       sd->pop();
316   }
317 
318   for(;;)
319   {
320     if (sh.fileposition > stopreadpos || streamreader(sh)<=0)
321       return; // data does not reach the point in time from which we like to start playing
322     if (sd->empty())
323       continue;
324 
325     streamdata::itemlisttype::const_iterator it=sd->itemlist().begin();
326     int pop=1;
327     pts_t pts=AV_NOPTS_VALUE;
328     for(++it;it!=sd->itemlist().end();++it,++pop)
329       if (it->headerhaspts()) //if (streamdata::headerhaspts(it->header))
330       {
331         pts=it->headerpts(startpts);
332         break;
333       }
334     if (pts==(pts_t)AV_NOPTS_VALUE)
335       continue;
336     if (pts<=startpts)
337       sd->pop(pop);
338     if (pts>=startpts)
339       break;
340   }
341 
342   while (streamreader(sh)>0)
343   {
344     streamdata::itemlisttype::const_reverse_iterator it=sd->itemlist().rbegin();
345     while(it!=sd->itemlist().rend())
346       if (it->headerhaspts())
347         break;
348       else
349         --it;
350 
351     if (it==sd->itemlist().rend())
352       continue;
353 
354     if (it->headerpts(stoppts)>stoppts)
355       break;
356   }
357 
358   sd->audio_addpts();
359 
360   uint32_t startbufferpos=sd->closestptsbufferpos(startpts);
361   uint32_t stopbufferpos=sd->closestptsbufferpos(stoppts);
362 
363   if (stopbufferpos>startbufferpos)
364   {
365     const stream &S=s[audiostream(aud)];
366 
367     if (S.type==streamtype::ac3audio)
368       playaudio_ac3(sd->getdata(startbufferpos),stopbufferpos-startbufferpos);
369     else
370       playaudio_mp2(sd->getdata(startbufferpos),stopbufferpos-startbufferpos);
371   }
372 }
373 #else // HAVE_LIB_AO
playaudio(int,int,int)374 void mpgfile::playaudio(int, int, int)
375 {
376 }
377 #endif // HAVE_LIB_AO
378 
savempg(muxer & mux,int start,int stop,int savedpics,int savepics,logoutput * log)379 void mpgfile::savempg(muxer &mux, int start, int stop, int savedpics, int savepics, logoutput *log)
380 {
381   if (start<0)
382     start=0;
383   if (start>pictures)
384     start=pictures;
385   if (stop<0)
386     stop=0;
387   if (stop>pictures)
388     stop=pictures;
389   if (start==stop)
390     return;
391   if (stop<start)
392   {
393     int x=start;
394     start=stop;
395     stop=x;
396   }
397 
398   int seekpic=idx.indexnr(start);
399   int framerate = mpgfile::frameratescr[idx[seekpic].getframerate()];
400   bool fixedstart=true;
401 
402   if (mux.isempty())
403   {
404     fixedstart=false;
405     mux.unsetempty();
406     pts_t startpts = framerate / 300;
407     for (int i=0;i<MAXAVSTREAMS;++i)
408       mux.setpts(i,startpts);
409   }
410 
411   pts_t videostartpts=idx[seekpic].getpts();
412   pts_t videostoppts=idx[idx.indexnr(stop)].getpts();
413   pts_t videooffset=videostartpts-mux.getpts(VIDEOSTREAM);
414   pts_t audiopts[MAXAUDIOSTREAMS];
415   pts_t audiostartpts[MAXAUDIOSTREAMS];
416   pts_t audiooffset[MAXAUDIOSTREAMS];
417   for(int a=0;a<MAXAUDIOSTREAMS;++a)
418   {
419     audiooffset[a]=videooffset;
420     audiostartpts[a]=audiopts[a]=videostartpts;
421   }
422   pts_t shift=0;
423 
424   {
425     dvbcut_off_t start_pos = idx[idx.indexnr(start)].getpos().fileposition();
426     dvbcut_off_t stop_pos = idx[idx.indexnr(stop)].getpos().fileposition();
427     dvbcut_off_t bytes = stop_pos - start_pos;
428     pts_t delta_pts = (pts_t)(stop - start) * framerate / 300;
429     double mux_rate = (double)bytes * 9e4 / (double)delta_pts;
430     if (log) {
431       //: Placeholder will be replaced with floating point number
432       log->printinfo(QCoreApplication::translate("mpgfile", "Estimated mux rate: %1 MB/s").arg(mux_rate * 1e-6, 0, 'f', 2));
433     }
434   }
435 
436   while (seekpic>0 && idx[seekpic].getpts()>=videostartpts-180000)
437     --seekpic;
438 
439   dvbcut_off_t tpos;
440   {
441     int stoppic=idx.indexnr(start);
442     while (stoppic<pictures &&
443            (idx[stoppic].getpts()<videostartpts+180000 || !idx[stoppic].getseqheader()))
444       ++stoppic;
445     tpos=idx[stoppic].getpos().packetposition();
446   }
447 
448   streamhandle sh(idx[seekpic].getpos().packetposition());
449   streamdata *vsd=sh.newstream(VIDEOSTREAM,s[VIDEOSTREAM].type,istransportstream());
450   for (int a=0;a<MAXAUDIOSTREAMS;++a)
451     if (mux.streampresent(audiostream(a)))
452       sh.newstream(audiostream(a),s[audiostream(a)].type,istransportstream());
453 
454   while (sh.fileposition<tpos)
455     if (streamreader(sh)<0)
456       break;
457 
458   for (int a=0;a<MAXAUDIOSTREAMS;++a)
459     if (streamdata *sd=sh.stream[audiostream(a)])
460     {
461       pts_t tpts=videostartpts-mux.getpts(VIDEOSTREAM)+mux.getpts(audiostream(a));
462       sd->audio_addpts();
463       uint32_t startbufferpos=sd->ptsbufferpos(tpts);
464       if (startbufferpos>sd->getoffset())
465         sd->discard(startbufferpos-sd->getoffset());
466       sd->audio_addpts(0,true);
467       startbufferpos=sd->closestptsbufferpos(tpts);
468       if (startbufferpos>sd->getoffset())
469         sd->discard(startbufferpos-sd->getoffset());
470 
471       pts_t apts=sd->itemlist().front().headerpts(tpts);
472       audiostartpts[a]=apts;
473       if (apts>=0)
474       {
475         if (fixedstart)
476           audiooffset[a]=videooffset-tpts+apts;
477         else if (tpts-apts>shift)
478           shift=tpts-apts;
479       }
480 
481     }
482 
483   if (!fixedstart)
484   {
485     videooffset-=shift;
486     for(int a=0;a<MAXAUDIOSTREAMS;++a)
487       audiooffset[a]=videooffset;
488   }
489 
490   pts_t audiostoppts[MAXAUDIOSTREAMS];
491   for(int a=0;a<MAXAUDIOSTREAMS;++a)
492     audiostoppts[a]=videostoppts-videooffset+audiooffset[a];
493 
494   int firstseqhdr=nextseqheader(start);
495   {
496     filepos_t copystart=idx[idx.indexnr(firstseqhdr)].getpos();
497     vsd->discard(vsd->fileposbufferpos(copystart)-vsd->getoffset());
498   }
499   bool isfirstpic=true, isfirstseq=true;
500   int firstseqnr=idx[idx.indexnr(firstseqhdr)].getsequencenumber();
501 
502   if (firstseqhdr>start)
503   {
504     recodevideo(mux,start,firstseqhdr,videooffset,savedpics,savepics,log);
505     savedpics+=firstseqhdr-start;
506   }
507 
508   int copystop=stop; // first picture not to write to stream
509   while (copystop<pictures && idx[idx.indexnr(copystop)].isbframe())
510     ++copystop;
511   copystop=idx.indexnr(copystop);
512 
513   int streampic=idx.indexnr(firstseqhdr);
514 
515   while (!log || !log->cancelled())
516   {
517     int packetsread;
518     for (packetsread=0;packetsread<20;++packetsread)
519       if (streamreader(sh)<=0)
520         break;
521     if (packetsread==0)
522       break;
523 
524     // copy video
525     if (vsd)
526       for(;;)
527       {
528         if (streampic>=copystop)
529         {
530           vsd=0;
531           sh.delstream(VIDEOSTREAM);
532           break;
533         }
534 
535         uint32_t picsize=vsd->fileposbufferpos(idx[streampic+1].getpos())-vsd->getoffset();
536         if (picsize>=vsd->inbytes())
537           break;
538 
539         if (!isfirstpic && idx[streampic].getseqheader())
540           isfirstseq=false;
541         isfirstpic=false;
542 
543         int seqoff=0;
544         if (!isfirstseq || idx[streampic].getsequencenumber()>=firstseqnr)
545         {
546           if (isfirstseq && firstseqnr>0) // need to subtract offset from picture sequence number
547           {
548             uint8_t *d=(uint8_t*) vsd->getdata();
549 
550             for (unsigned int j=0;j+5<picsize;)
551             {
552               if (d[2]&0xfe)
553                 j+=3;
554               else
555                 if (*(u_int32_t*)&d[j]==mbo32(0x00000100))
556                 {
557                   int seqpic=(d[j+4]<<2)|((d[j+5]>>6)&0x03);
558                   seqpic-=firstseqnr;
559                   d[j+4]=seqpic>>2;
560                   d[j+5]=(d[j+5]&0x3f)|((seqpic<<6)&0xc0);
561                   break;
562                 }
563                 else
564                   ++j;
565             }
566             seqoff=firstseqnr;
567           }
568           pts_t vidpts=idx[streampic].getpts()-videooffset;
569           pts_t viddts=vidpts;
570           if (!idx[streampic].isbframe())
571           {
572             viddts=mux.getdts(VIDEOSTREAM);
573             mux.setdts(VIDEOSTREAM,vidpts);
574           }
575           if (idx[streampic].getseqheader())
576           {
577             int tcpic=streampic;
578             while (tcpic < copystop && idx[tcpic].getsequencenumber() != seqoff)
579               ++tcpic;
580             pts_t tcpts=idx[tcpic].getpts()-videooffset;
581             fixtimecode((uint8_t*)vsd->getdata(),picsize,tcpts);
582           }
583           if (!mux.putpacket(VIDEOSTREAM,vsd->getdata(),picsize,vidpts,viddts,
584                              idx[streampic].isiframe() ? MUXER_FLAG_KEY:0  ))
585             {
586               if (log) {
587                 //: Placeholder will be replaced with streampic number
588                 log->printwarning(QCoreApplication::translate("mpgfile", "putpacket(streampic=%1) returned false").arg(streampic));
589               } else {
590                 fprintf(stderr,"WARN: putpacket(streampic=%d) returned false\n",streampic);
591               }
592             }
593         }
594 
595         vsd->discard(picsize);
596         ++streampic;
597 
598         if (log && savepics>0)
599           log->setprogress(++savedpics*1000/savepics);
600       }
601 
602     bool haveaudio=false;
603 
604     for (int a=0;a<MAXAUDIOSTREAMS;++a)
605       if (streamdata * const sd=sh.stream[audiostream(a)])
606       {
607         bool stopped=false;
608         sd->audio_addpts();
609         streamdata::itemlisttype::const_iterator nx,it;
610 
611 	while ((it = sd->itemlist().begin())!=sd->itemlist().end() &&
612 	       !it->is_frame())
613 	  sd->pop();
614 	if (it!=sd->itemlist().end())
615         while(!stopped)
616         {
617           audiopts[a]=it->headerpts(audiopts[a]);
618           if (audiopts[a]>=audiostoppts[a])
619           {
620             audiostoppts[a]=audiopts[a];
621             stopped=true;
622             break;
623           }
624           nx=it;
625           ++nx;
626           while (nx!=sd->itemlist().end() && !nx->is_frame())
627             ++nx;
628           if (nx==sd->itemlist().end())
629             break;
630           uint32_t bytes=nx->bufferposition-it->bufferposition;
631           pts_t nxheaderpts=nx->headerpts(audiopts[a]);
632 
633           if (nxheaderpts>=audiostoppts[a])
634           {
635             if (nxheaderpts-audiostoppts[a]>audiostoppts[a]-audiopts[a])
636             {
637               bytes=0;
638               audiostoppts[a]=audiopts[a];
639             }
640             else
641               audiostoppts[a]=nxheaderpts;
642             stopped=true;
643           }
644 
645           if (nx->bufferposition<it->bufferposition)
646           {
647 
648             for(it=sd->itemlist().begin();it!=sd->itemlist().end();++it)
649               fprintf(stderr," fileposition:%ld/%d bufferposition:%d flags:%x pts:%s\n",
650                       it->fileposition.packetposition(),it->fileposition.packetoffset(),
651                       it->bufferposition,it->flags,ptsstring(it->pts).c_str());
652 
653             fprintf(stderr,"nx->bufferposition:%d it->bufferposition:%d\n",
654                     nx->bufferposition,it->bufferposition);
655 
656             for(int i=0;i<MAXAVSTREAMS;++i)
657               if (sh.stream[i])
658                 fprintf(stderr,"stream %d%s, itemlist.size():%lu\n",
659                         i,(sh.stream[i]==sd)?"*":"",sh.stream[i]->itemlist().size());
660 
661             abort();
662           }
663 
664           if (bytes>0)
665           {
666             pts_t pts=audiopts[a]-audiooffset[a];
667 	    //fprintf(stderr, "mux.put audio %d %lld\n", bytes, pts);
668             mux.putpacket(audiostream(a),sd->getdata(),bytes,pts,pts,MUXER_FLAG_KEY);
669 
670             sd->discard(bytes);
671           }
672           it=nx;
673         }
674 
675         if (stopped)
676           sh.delstream(audiostream(a));
677         else
678           haveaudio=true;
679       }
680 
681     if (!vsd &&!haveaudio)
682       break;
683   }
684 
685   if ((stop>nextseqheader(start)) && idx[idx.indexnr(stop-1)].isbframe())
686     // we didn't catch the last picture(s) yet
687   {
688     int startrecode=stop-1;
689     while (startrecode>0 && idx[idx.indexnr(startrecode-1)].isbframe())
690       --startrecode;
691     recodevideo(mux,startrecode,stop,videooffset,savedpics,savepics,log);
692   }
693 
694   // output info on audio stream timings
695   if (log)
696     for (int a=0;a<MAXAUDIOSTREAMS;++a)
697       if (mux.streampresent(audiostream(a)))
698       {
699         float starts=float(audiostartpts[a]-videostartpts)/90.;
700         float stops=float(audiostoppts[a]-videostoppts)/90.;
701         float shift=float(audiooffset[a]-videooffset)/90.;
702 
703         if (starts >= shift) {
704             log->printinfo(QCoreApplication::translate("mpgfile", "Audio channel %1: starts %2 milliseconds after video")
705                 .arg(a+1)
706                 .arg(fabsf(starts-shift), 0, 'f', 3));
707         } else {
708             log->printinfo(QCoreApplication::translate("mpgfile", "Audio channel %1: starts %2 milliseconds before video")
709                 .arg(a+1)
710                 .arg(fabsf(starts-shift), 0, 'f', 3));
711         }
712 
713         if (stops >= shift) {
714             log->printinfo(QCoreApplication::translate("mpgfile", "Audio channel %1: stops %2 milliseconds after video")
715                 .arg(a+1)
716                 .arg(fabsf(stops-shift), 0, 'f', 3));
717         } else {
718             log->printinfo(QCoreApplication::translate("mpgfile", "Audio channel %1: stops %2 milliseconds before video")
719                 .arg(a+1)
720                 .arg(fabsf(stops-shift), 0, 'f', 3));
721         }
722 
723         log->printinfo(QCoreApplication::translate("mpgfile", "Audio channel %1: delayed %2 milliseconds")
724             .arg(a+1)
725             .arg(shift, 0, 'f', 3));
726         log->print("");
727       }
728 
729   mux.setpts(VIDEOSTREAM, videostoppts-videooffset);
730   for(int a=0;a<MAXAUDIOSTREAMS;++a)
731     mux.setpts(audiostream(a), audiostoppts[a]-audiooffset[a]);
732 }
733 
recodevideo(muxer & mux,int start,int stop,pts_t offset,int savedpics,int savepics,logoutput * log)734 void mpgfile::recodevideo(muxer &mux, int start, int stop, pts_t offset,int savedpics,int savepics, logoutput *log)
735 {
736   if (log) {
737 #if QT_VERSION >= 0x050000
738       log->printinfo(QCoreApplication::translate("mpgfile", "Recoding %n pictures", "", stop-start));
739 #else
740       log->printinfo(QCoreApplication::translate("mpgfile", "Recoding %n pictures", "", QCoreApplication::CodecForTr, stop-start));
741 #endif
742   }
743 
744   std::list<avframe*> framelist;
745   decodegop(start,stop,framelist);
746 
747   AVCodecContext *avcc=s[VIDEOSTREAM].avcc;
748   if (!avcc)
749     return;
750   s[VIDEOSTREAM].setvideoencodingparameters(time_base_num, time_base_den, !framelist.empty() ? (*framelist.front())->interlaced_frame : 0);
751 
752   if (int rv=avcodec_open2(avcc, s[VIDEOSTREAM].enc, NULL))
753   {
754     if (log) {
755       //: Placeholder will be replaced with return value (integer)
756       log->printerror(QCoreApplication::translate("mpgfile", "avcodec_open(mpeg2video_encoder) returned %1").arg(rv));
757     }
758     return ;
759   }
760 
761   buffer m2v(4<<20);
762 
763   int p=0;
764   int outpicture=start;
765   pts_t startpts=idx[idx.indexnr(start)].getpts();
766   while (outpicture<stop)
767   {
768     AVPacket pkt;
769     u_int8_t *buf=(u_int8_t*)m2v.writeptr();
770     int ret, got_output;
771 
772     av_init_packet(&pkt);
773     pkt.data = buf;
774     pkt.size = m2v.getsize();
775 
776     if (!framelist.empty())
777     {
778       avframe &f=*framelist.front();
779 
780       f->pts=idx[idx.indexnr(start+p)].getpts()-startpts;
781       f->coded_picture_number=f->display_picture_number=p;
782       f->key_frame=(p==0)?1:0;
783       f->pict_type=(p==0)?AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
784       ret = avcodec_encode_video2(avcc, &pkt, f, &got_output);
785 
786       delete framelist.front();
787       framelist.pop_front();
788       ++p;
789 
790       if (ret < 0 || !got_output)
791         continue;
792     }
793     else
794     {
795       fprintf(stderr,"trying to call avcodec_encode_video with frame=0\n");
796       ret = avcodec_encode_video2(avcc, &pkt, NULL, &got_output);
797       fprintf(stderr,"...back I am.\n");
798 
799       if (ret < 0 || !got_output)
800         break;
801     }
802 
803     pts_t vidpts=idx[idx.indexnr(outpicture)].getpts()-offset;
804     pts_t viddts=mux.getdts(VIDEOSTREAM);
805     mux.setdts(VIDEOSTREAM,vidpts);
806     fixtimecode(pkt.data, pkt.size, vidpts);
807     mux.putpacket(VIDEOSTREAM,pkt.data,pkt.size,vidpts,viddts,
808                   (pkt.flags & AV_PKT_FLAG_KEY)?MUXER_FLAG_KEY:0 );
809     ++outpicture;
810 
811     if (log && savepics>0)
812       log->setprogress(++savedpics*1000/savepics);
813   }
814 
815   for(std::list<avframe*>::iterator fit=framelist.begin();fit!=framelist.end();++fit)
816     delete *fit;
817   avcodec_close(avcc);
818 }
819 
fixtimecode(uint8_t * buf,int len,pts_t pts)820 void mpgfile::fixtimecode(uint8_t *buf, int len, pts_t pts)
821 {
822   int frc=-1;
823   int i=0;
824   for (;;)
825   {
826     if (i+8>len)
827       return;
828     else if (buf[i+2]&0xfe)
829       i+=3;
830     else if (buf[i]!=0 || buf[i+1]!=0 || buf[i+2]!=1)
831       i+=1;
832     else if (buf[i+3]==0xb3)
833     {	// sequence header
834       frc=buf[i+7]&0x0f;
835       i+=12;
836     }
837     else if (buf[i+3]==0xb8)	// GOP header
838       break;
839     else
840       i+=4;
841   }
842   buf+=i;
843   buf[4]=0x00;
844   buf[5]=0x00;
845   buf[6]=0x08;
846   buf[7]&=0x7f;
847   if (frc==-1)
848     return;
849   if (frc==1 || frc==4 || frc==7)
850     ++frc;	// use nearest integer
851   int framerate=27000000/frameratescr[frc];
852   int ss=pts/90000;
853   int mm=ss/60; ss %= 60;
854   int hh=mm/60; mm %= 60;
855   int pp=pts%90000;
856   pp=(pp*framerate)/90000;
857   buf[4] = ((hh<<2) & 0x7c) | ((mm>>4) & 0x03);
858   buf[5] = ((mm<<4) & 0xf0) | ((ss>>3) & 0x07) | 0x08;
859   buf[6] = ((ss<<5) & 0xe0) | ((pp>>1) & 0x1f);
860   buf[7] |= (pp<<7) & 0x80;
861 }
862 
863 // general purpose utility function to
864 // read a binary file to memory for further processing
865 // ATTENTION: BE SURE YOU HAVE ENOUGH!!! */
readfile(std::string filename,uint8_t ** buffer)866 ssize_t mpgfile::readfile(std::string filename, uint8_t **buffer) {
867 
868   FILE *pFile;
869   size_t len, lSize;
870 
871   pFile = fopen(filename.c_str() , "rb");
872   if (pFile==NULL) return -1;
873 
874   // obtain file size
875   fseek (pFile , 0 , SEEK_END);
876   lSize = ftell(pFile);
877   rewind(pFile);
878 
879   // allocate memory to contain the whole file
880   *buffer = (uint8_t*) malloc(sizeof(uint8_t)*lSize);
881   if (buffer == NULL) {
882     fclose(pFile);
883     return -2;
884   }
885 
886   // copy the file into the buffer
887   len = fread(*buffer, 1, lSize, pFile);
888   if (len != lSize) {
889     fclose(pFile);
890     free(buffer);
891     return -3;
892   }
893 
894   fclose(pFile);
895   return len;
896 
897 }
898