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