MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
mpeg2fix.cpp
Go to the documentation of this file.
1 //To Do
2 //support missing audio frames
3 //support analyze-only mode
4 
5 // C headers
6 #include <cstdlib>
7 #include <cstdio>
8 
9 // POSIC headers
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <getopt.h>
13 #include <stdint.h>
14 #include <sys/stat.h>
15 
16 #include "config.h"
17 #include "mpeg2fix.h"
18 
19 #include <QList>
20 #include <QQueue>
21 #include <QMap>
22 #include <QFileInfo>
23 
24 #include "mythlogging.h"
25 #include "mythdate.h"
26 #include "mthread.h"
27 
28 #ifdef USING_MINGW
29 #include <winsock2.h>
30 #else
31 #include <netinet/in.h>
32 #endif
33 
34 #ifndef O_LARGEFILE
35 #define O_LARGEFILE 0
36 #endif
37 
38 #define ATTR_ALIGN(align) __attribute__ ((__aligned__ (align)))
39 
40 static void *my_malloc(unsigned size, mpeg2_alloc_t reason)
41 {
42  (void)reason;
43  char * buf;
44 
45  if (size)
46  {
47  buf = (char *) malloc (size + 63 + sizeof (void **));
48  if (buf)
49  {
50  char * align_buf;
51  memset(buf, 0, size + 63 + sizeof (void **));
52  align_buf = buf + 63 + sizeof (void **);
53  align_buf -= (long)align_buf & 63;
54  *(((void **)align_buf) - 1) = buf;
55  return align_buf;
56  }
57  }
58 
59  return NULL;
60 }
61 
62 static void my_av_print(void *ptr, int level, const char* fmt, va_list vl)
63 {
64  (void) ptr;
65 
66  static QString full_line("");
67  char str[256];
68 
69  if (level > AV_LOG_INFO)
70  return;
71  vsprintf(str, fmt, vl);
72 
73  full_line += QString(str);
74  if (full_line.endsWith("\n"))
75  {
76  full_line.truncate(full_line.length() - 1);
77  LOG(VB_GENERAL, LOG_INFO, full_line);
78  full_line = QString("");
79  }
80 }
81 
82 static QString PtsTime(int64_t pts)
83 {
84  bool is_neg = false;
85  if (pts < 0)
86  {
87  pts = -pts;
88  is_neg = true;
89  }
90  QString msg;
91  return(msg.sprintf("%s%02d:%02d:%02d.%03d", (is_neg) ? "-" : "",
92  (unsigned int)(pts / 90000.) / 3600,
93  ((unsigned int)(pts / 90000.) % 3600) / 60,
94  ((unsigned int)(pts / 90000.) % 3600) % 60,
95  (((unsigned int)(pts / 90.) % 3600000) % 60000) % 1000));
96 }
97 
98 PTSOffsetQueue::PTSOffsetQueue(int vidid, QList<int> keys, int64_t initPTS)
99 {
100  QList<int>::iterator it;
101  poq_idx_t idx;
102  vid_id = vidid;
103  keyList = keys;
104  keyList.append(vid_id);
105 
106  idx.newPTS = initPTS;
107  idx.pos_pts = 0;
108  idx.framenum = 0;
109  idx.type = 0;
110 
111  for (it = keyList.begin(); it != keyList.end(); ++it)
112  offset[*it].push_back(idx);
113 }
114 
115 int64_t PTSOffsetQueue::Get(int idx, AVPacket *pkt)
116 {
117  QList<poq_idx_t>::iterator it;
118  int64_t value = offset[idx].first().newPTS;
119  bool done = false;
120 
121  if (!pkt)
122  return value;
123 
124  //Be aware: the key for offset can be either a file position OR a PTS
125  //The type is defined by type (0==PTS, 1==Pos)
126  while (offset[idx].count() > 1 && !done)
127  {
128  it = ++offset[idx].begin();
129  if ((((*it).type == 0) && (pkt->pts >= (*it).pos_pts) /* PTS type */) ||
130  (((*it).type == 1) /* Pos type */ &&
131  ((pkt->pos >= (*it).pos_pts) || (pkt->duration > (*it).framenum))))
132  {
133  offset[idx].pop_front();
134  value = offset[idx].first().newPTS;
135  }
136  else
137  done = true;
138  }
139  return value;
140 }
141 
142 void PTSOffsetQueue::SetNextPTS(int64_t newPTS, int64_t atPTS)
143 {
144  QList<int>::iterator it;
145  poq_idx_t idx;
146 
147  idx.newPTS = newPTS;
148  idx.pos_pts = atPTS;
149  idx.type = 0;
150  idx.framenum = 0;
151 
152  for (it = keyList.begin(); it != keyList.end(); ++it)
153  offset[*it].push_back(idx);
154 }
155 
156 void PTSOffsetQueue::SetNextPos(int64_t newPTS, AVPacket &pkt)
157 {
158  QList<int>::iterator it;
159  int64_t delta = MPEG2fixup::diff2x33(newPTS, offset[vid_id].last().newPTS);
160  poq_idx_t idx;
161 
162  idx.pos_pts = pkt.pos;
163  idx.framenum = pkt.duration;
164  idx.type = 1;
165 
166  LOG(VB_FRAME, LOG_INFO, QString("Offset %1 -> %2 (%3) at %4")
167  .arg(PtsTime(offset[vid_id].last().newPTS))
168  .arg(PtsTime(newPTS)).arg(PtsTime(delta)).arg(pkt.pos));
169  for (it = keyList.begin(); it != keyList.end(); ++it)
170  {
171  idx.newPTS = newPTS;
172  offset[*it].push_back(idx);
173  idx.newPTS = delta;
174  orig[*it].push_back(idx);
175  }
176 }
177 
178 int64_t PTSOffsetQueue::UpdateOrigPTS(int idx, int64_t &origPTS, AVPacket &pkt)
179 {
180  int64_t delta = 0;
181  QList<poq_idx_t> *dltaList = &orig[idx];
182  while (dltaList->count() &&
183  (pkt.pos >= dltaList->first().pos_pts ||
184  pkt.duration > dltaList->first().framenum))
185  {
186  if (dltaList->first().newPTS >= 0)
187  ptsinc((uint64_t *)&origPTS, 300 * dltaList->first().newPTS);
188  else
189  ptsdec((uint64_t *)&origPTS, -300 * dltaList->first().newPTS);
190  delta += dltaList->first().newPTS;
191  dltaList->pop_front();
192  LOG(VB_PROCESS, LOG_INFO,
193  QString("Moving PTS offset of stream %1 by %2")
194  .arg(idx).arg(PtsTime(delta)));
195  }
196  return (delta);
197 }
198 
199 MPEG2fixup::MPEG2fixup(const QString &inf, const QString &outf,
200  frm_dir_map_t *deleteMap,
201  const char *fmt, int norp, int fixPTS, int maxf,
202  bool showprog, int otype, void (*update_func)(float),
203  int (*check_func)())
204 {
205  displayFrame = 0;
206 
207  infile = inf;
208  rx.outfile = outf;
209  rx.done = 0;
210  format = fmt;
211  no_repeat = norp;
212  fix_PTS = fixPTS;
213  maxframes = maxf;
214  rx.otype = otype;
215 
216  real_file_end = file_end = false;
217 
218  use_secondary = false;
219  framenum = 0;
220  discard = 0;
221  if (deleteMap && deleteMap->count())
222  {
223  delMap = *deleteMap;
224  if (delMap.contains(0))
225  {
226  discard = 1;
227  delMap.remove(0);
228  }
229  if (delMap.begin().value() == MARK_CUT_END)
230  discard = 1;
231  use_secondary = true;
232  }
233 
234  ext_count = 0;
235  vid_id = -1;
239 
240  av_register_all();
241  av_log_set_callback(my_av_print);
242 
243  pthread_mutex_init(&rx.mutex, NULL);
244  pthread_cond_init(&rx.cond, NULL);
245 
246  //await multiplexer initialization (prevent a deadlock race)
247  pthread_mutex_lock(&rx.mutex);
248  pthread_create(&thread, NULL, ReplexStart, this);
249  pthread_cond_wait(&rx.cond, &rx.mutex);
250  pthread_mutex_unlock(&rx.mutex);
251 
252  //initialize progress stats
253  showprogress = showprog;
254  update_status = update_func;
255  check_abort = check_func;
257  {
258  if (update_status)
259  {
260  status_update_time = 20;
261  update_status(0);
262  }
263  else
264  status_update_time = 5;
267 
268  const QFileInfo finfo(inf);
269  filesize = finfo.size();
270  }
271 }
272 
274 {
277 
278  if (inputFC)
279  avformat_close_input(&inputFC);
280 
281  MPEG2frame *tmpFrame;
282 
283  while (vFrame.count())
284  {
285  tmpFrame = vFrame.takeFirst();
286  delete tmpFrame;
287  }
288 
289  while (vSecondary.count())
290  {
291  tmpFrame = vSecondary.takeFirst();
292  delete tmpFrame;
293  }
294 
295  for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
296  {
297  FrameList *af = (*it);
298  while (af->count())
299  {
300  tmpFrame = af->takeFirst();
301  delete tmpFrame;
302  }
303  delete af;
304  }
305 
306  while (framePool.count())
307  delete framePool.dequeue();
308 }
309 
310 //#define MPEG2trans_DEBUG
311 #define MATCH_HEADER(ptr) (((ptr)[0] == 0x00) && ((ptr)[1] == 0x00) && ((ptr)[2] == 0x01))
312 
313 static void SETBITS(unsigned char *ptr, long value, int num)
314 {
315  static int sb_pos;
316  static unsigned char *sb_ptr = 0;
317  uint32_t sb_long, mask;
318  int offset, offset_r, offset_b;
319 
320  if (ptr != 0)
321  {
322  sb_ptr = ptr;
323  sb_pos = 0;
324  }
325 
326  offset = sb_pos >> 3;
327  offset_r = sb_pos & 0x07;
328  offset_b = 32 - offset_r;
329  mask = ~(((1 << num) - 1) << (offset_b - num));
330  sb_long = ntohl(*((uint32_t *) (sb_ptr + offset)));
331  value = value << (offset_b - num);
332  sb_long = (sb_long & mask) + value;
333  *((uint32_t *)(sb_ptr + offset)) = htonl(sb_long);
334 }
335 
336 void MPEG2fixup::dec2x33(int64_t *pts1, int64_t pts2)
337 {
338  *pts1 = udiff2x33(*pts1, pts2);
339 }
340 
341 void MPEG2fixup::inc2x33(int64_t *pts1, int64_t pts2)
342 {
343  *pts1 = (*pts1 + pts2) % MAX_PTS;
344 }
345 
346 int64_t MPEG2fixup::udiff2x33(int64_t pts1, int64_t pts2)
347 {
348  int64_t diff;
349 
350  diff = pts1 - pts2;
351 
352  if (diff < 0){
353  diff = MAX_PTS + diff;
354  }
355  return (diff % MAX_PTS);
356 }
357 
358 int64_t MPEG2fixup::diff2x33(int64_t pts1, int64_t pts2)
359 {
360  switch (cmp2x33(pts1, pts2))
361  {
362  case 0:
363  return 0;
364  break;
365 
366  case 1:
367  case -2:
368  return (pts1 - pts2);
369  break;
370 
371  case 2:
372  return (pts1 + MAX_PTS - pts2);
373  break;
374 
375  case -1:
376  return (pts1 - (pts2 + MAX_PTS));
377  break;
378  }
379 
380  return 0;
381 }
382 
383 int64_t MPEG2fixup::add2x33(int64_t pts1, int64_t pts2)
384 {
385  int64_t tmp = pts1 + pts2;
386  if (tmp >= 0)
387  return (pts1 + pts2) % MAX_PTS;
388  return (tmp + MAX_PTS);
389 }
390 
391 int MPEG2fixup::cmp2x33(int64_t pts1, int64_t pts2)
392 {
393  int ret;
394 
395  if (pts1 > pts2)
396  {
397  if ((uint64_t)(pts1 - pts2) > MAX_PTS/2)
398  ret = -1;
399  else
400  ret = 1;
401  }
402  else if (pts1 == pts2)
403  ret = 0;
404  else
405  {
406  if ((uint64_t)(pts2 - pts1) > MAX_PTS/2)
407  ret = 2;
408  else
409  ret = -2;
410  }
411  return ret;
412 }
413 
414 int MPEG2fixup::FindMPEG2Header(uint8_t *buf, int size, uint8_t code)
415 {
416  int i;
417 
418  for (i = 0; i < size; i++)
419  {
420  if (MATCH_HEADER(buf + i) && buf[i + 3] == code)
421  return i;
422  }
423 
424  return 0;
425 }
426 
427 //fill_buffers will signal the main thread to start decoding again as soon
428 //as it runs out of buffers. It will then wait for the buffer to completely
429 //fill before returning. In this way, the 2 threads are never running
430 // concurrently
431 static int fill_buffers(void *r, int finish)
432 {
433  MPEG2replex *rx = (MPEG2replex *)r;
434 
435  if (finish)
436  return 0;
437 
438  return (rx->WaitBuffers());
439 }
440 
442  done(0), otype(0),
443  ext_count(0), mplex(0)
444 {
445  memset(&vrbuf, 0, sizeof(vrbuf));
446  memset(extrbuf, 0, sizeof(extrbuf));
447  memset(&index_vrbuf, 0, sizeof(index_vrbuf));
448  memset(index_extrbuf, 0, sizeof(index_extrbuf));
449  memset(exttype, 0, sizeof(exttype));
450  memset(exttypcnt, 0, sizeof(exttypcnt));
451  memset(extframe, 0, sizeof(extframe));
452  memset(&seq_head, 0, sizeof(seq_head));
453 }
454 
456 {
457  if (vrbuf.size)
459  if (index_vrbuf.size)
461 
462  for (int i = 0; i < ext_count; i++)
463  {
464  if (extrbuf[i].size)
465  ring_destroy(&extrbuf[i]);
466  if (index_extrbuf[i].size)
468  }
469 }
470 
472 {
473  pthread_mutex_lock( &mutex );
474  while (1)
475  {
476  int i, ok = 1;
477 
478  if (ring_avail(&index_vrbuf) < sizeof(index_unit))
479  ok = 0;
480 
481  for (i = 0; i < ext_count; i++)
482  if (ring_avail(&index_extrbuf[i]) < sizeof(index_unit))
483  ok = 0;
484 
485  if (ok || done)
486  break;
487 
488  pthread_cond_signal(&cond);
489  pthread_cond_wait(&cond, &mutex);
490  }
491  pthread_mutex_unlock(&mutex);
492 
493  if (done)
494  {
495  finish_mpg(mplex);
496  pthread_exit(NULL);
497  }
498 
499  return 0;
500 }
501 
503 {
504  MThread::ThreadSetup("MPEG2Replex");
505  MPEG2fixup *m2f = (MPEG2fixup *) data;
506  m2f->rx.Start();
508  return NULL;
509 }
510 
512 {
513  int start = 1;
514  multiplex_t mx;
515 
516  //array defines number of allowed audio streams
517  // note that although only 1 stream is currently supported, multiplex.c
518  // expects the size to by N_AUDIO
519  int ext_ok[N_AUDIO];
520  int video_ok = 0;
521 
522  //seq_head should be set only for the 1st sequence header. If a new
523  // seq header comes which is different, we are screwed.
524 
525 
526  int video_delay = 0, audio_delay = 0;
527  int fd_out;
528 
529  memset(&mx, 0, sizeof(mx));
530  memset(ext_ok, 0, sizeof(ext_ok));
531 
532  mx.priv = (void *)this;
533 
534  fd_out = open(outfile.toLocal8Bit().constData(),
535  O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
536 
537  //await buffer fill
538  pthread_mutex_lock(&mutex);
539  pthread_cond_signal(&cond);
540  pthread_cond_wait(&cond, &mutex);
541  pthread_mutex_unlock(&mutex);
542 
543  mplex = &mx;
544 
546  video_delay, audio_delay, fd_out, fill_buffers,
547  &vrbuf, &index_vrbuf, extrbuf, index_extrbuf, otype);
548  setup_multiplex(&mx);
549 
550  while (1)
551  {
552  check_times( &mx, &video_ok, ext_ok, &start);
553  write_out_packs( &mx, video_ok, ext_ok);
554  }
555 }
556 
557 #define INDEX_BUF (sizeof(index_unit) * 200)
559 {
560  // index_vrbuf contains index_units which describe a video frame
561  // it also contains the start pos of the next frame
562  // index_arbuf only uses, pts, framesize, length, start, (active, err)
563 
564  //this should support > 100 frames
565  uint32_t memsize = vFrame.first()->mpeg2_seq.width *
566  vFrame.first()->mpeg2_seq.height * 10;
567  ring_init(&rx.vrbuf, memsize);
568  ring_init(&rx.index_vrbuf, INDEX_BUF);
569 
570  memset(rx.exttype, 0, sizeof(rx.exttype));
571  memset(rx.exttypcnt, 0, sizeof(rx.exttypcnt));
572  int mp2_count = 0, ac3_count = 0;
573  for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
574  {
575  int i = aud_map[it.key()];
576  AVDictionaryEntry *metatag =
577  av_dict_get(inputFC->streams[it.key()]->metadata,
578  "language", NULL, 0);
579  char *lang = metatag ? metatag->value : (char *)"";
580  ring_init(&rx.extrbuf[i], memsize / 5);
581  ring_init(&rx.index_extrbuf[i], INDEX_BUF);
582  rx.extframe[i].set = 1;
583  rx.extframe[i].bit_rate = getCodecContext(it.key())->bit_rate;
584  rx.extframe[i].framesize = (*it)->first()->pkt.size;
585  strncpy(rx.extframe[i].language, lang, 4);
586  switch(GetStreamType(it.key()))
587  {
588  case AV_CODEC_ID_MP2:
589  case AV_CODEC_ID_MP3:
590  rx.exttype[i] = 2;
591  rx.exttypcnt[i] = mp2_count++;
592  break;
593  case AV_CODEC_ID_AC3:
594  rx.exttype[i] = 1;
595  rx.exttypcnt[i] = ac3_count++;
596  break;
597  }
598  }
599 
600  //bit_rate/400
601  rx.seq_head.bit_rate = vFrame.first()->mpeg2_seq.byte_rate / 50;
602  rx.seq_head.frame_rate = (vFrame.first()->mpeg2_seq.frame_period +
603  26999999ULL) / vFrame.first()->mpeg2_seq.frame_period;
604 
606 }
607 
609 {
610  QString msg = QString("Id:%1 %2 V:%3").arg(f->pkt.stream_index)
611  .arg(PtsTime(f->pkt.pts))
612  .arg(ring_free(&rx.index_vrbuf) / sizeof(index_unit));
613 
614  if (ext_count)
615  {
616  msg += " EXT:";
617  for (int i = 0; i < ext_count; i++)
618  msg += QString(" %2")
619  .arg(ring_free(&rx.index_extrbuf[i]) / sizeof(index_unit));
620  }
621  LOG(VB_RPLXQUEUE, LOG_INFO, msg);
622 }
623 
625 {
626  index_unit iu;
627  ringbuffer *rb = 0, *rbi = 0;
628  int id = f->pkt.stream_index;
629 
630  memset(&iu, 0, sizeof(index_unit));
631  iu.frame_start = 1;
632 
633  if (id == vid_id)
634  {
635  rb = &rx.vrbuf;
636  rbi = &rx.index_vrbuf;
637  iu.frame = GetFrameTypeN(f);
638  iu.seq_header = f->isSequence;
639  iu.gop = f->isGop;
640 
641  iu.gop_off = f->gopPos - f->pkt.data;
642  iu.frame_off = f->framePos - f->pkt.data;
643  iu.dts = f->pkt.dts * 300;
644  }
645  else if (GetStreamType(id) == AV_CODEC_ID_MP2 ||
646  GetStreamType(id) == AV_CODEC_ID_MP3 ||
647  GetStreamType(id) == AV_CODEC_ID_AC3)
648  {
649  rb = &rx.extrbuf[aud_map[id]];
650  rbi = &rx.index_extrbuf[aud_map[id]];
651  iu.framesize = f->pkt.size;
652  }
653 
654  if (!rb || !rbi)
655  {
656  LOG(VB_GENERAL, LOG_ERR, "Ringbuffer pointers empty. No stream found");
657  return 1;
658  }
659 
660  iu.active = 1;
661  iu.length = f->pkt.size;
662  iu.pts = f->pkt.pts * 300;
663  pthread_mutex_lock( &rx.mutex );
664 
665  FrameInfo(f);
666  while (ring_free(rb) < (unsigned int)f->pkt.size ||
667  ring_free(rbi) < sizeof(index_unit))
668  {
669  int i, ok = 1;
670 
671  if (rbi != &rx.index_vrbuf &&
672  ring_avail(&rx.index_vrbuf) < sizeof(index_unit))
673  ok = 0;
674 
675  for (i = 0; i < ext_count; i++)
676  if (rbi != &rx.index_extrbuf[i] &&
677  ring_avail(&rx.index_extrbuf[i]) < sizeof(index_unit))
678  ok = 0;
679 
680  if (!ok && ring_free(rb) < (unsigned int)f->pkt.size &&
681  ring_free(rbi) >= sizeof(index_unit))
682  {
683  // increase memory to avoid deadlock
684  unsigned int inc_size = 10 * (unsigned int)f->pkt.size;
685  LOG(VB_GENERAL, LOG_NOTICE,
686  QString("Increasing ringbuffer size by %1 to avoid deadlock")
687  .arg(inc_size));
688 
689  if (!ring_reinit(rb, rb->size + inc_size))
690  ok = 1;
691  }
692  if (!ok)
693  {
694  pthread_mutex_unlock( &rx.mutex );
695  //deadlock
696  LOG(VB_GENERAL, LOG_ERR,
697  "Deadlock detected. One buffer is full when "
698  "the other is empty! Aborting");
699  return 1;
700  }
701 
702  pthread_cond_signal(&rx.cond);
703  pthread_cond_wait(&rx.cond, &rx.mutex);
704 
705  FrameInfo(f);
706  }
707 
708  if (ring_write(rb, f->pkt.data, f->pkt.size)<0){
709  pthread_mutex_unlock( &rx.mutex );
710  LOG(VB_GENERAL, LOG_ERR,
711  QString("Ring buffer overflow %1").arg(rb->size));
712  return 1;
713  }
714 
715  if (ring_write(rbi, (uint8_t *)&iu, sizeof(index_unit))<0){
716  pthread_mutex_unlock( &rx.mutex );
717  LOG(VB_GENERAL, LOG_ERR,
718  QString("Ring buffer overflow %1").arg(rbi->size));
719  return 1;
720  }
721  pthread_mutex_unlock(&rx.mutex);
722  last_written_pos = f->pkt.pos;
723  return 0;
724 }
725 
726 bool MPEG2fixup::InitAV(QString inputfile, const char *type, int64_t offset)
727 {
728  int ret;
729  QByteArray ifarray = inputfile.toLocal8Bit();
730  const char *ifname = ifarray.constData();
731 
732  AVInputFormat *fmt = NULL;
733 
734  if (type)
735  fmt = av_find_input_format(type);
736 
737  // Open recording
738  LOG(VB_GENERAL, LOG_INFO, QString("Opening %1").arg(inputfile));
739 
740  inputFC = NULL;
741 
742  ret = avformat_open_input(&inputFC, ifname, fmt, NULL);
743  if (ret)
744  {
745  LOG(VB_GENERAL, LOG_ERR,
746  QString("Couldn't open input file, error #%1").arg(ret));
747  return false;
748  }
749 
750  mkvfile = !strcmp(inputFC->iformat->name, "mkv") ? 1 : 0;
751 
752  if (offset)
753  av_seek_frame(inputFC, vid_id, offset, AVSEEK_FLAG_BYTE);
754 
755  // Getting stream information
756  ret = avformat_find_stream_info(inputFC, NULL);
757  if (ret < 0)
758  {
759  LOG(VB_GENERAL, LOG_ERR,
760  QString("Couldn't get stream info, error #%1").arg(ret));
761  avformat_close_input(&inputFC);
762  inputFC = NULL;
763  return false;
764  }
765 
766  // Dump stream information
767  if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_INFO))
768  av_dump_format(inputFC, 0, ifname, 0);
769 
770  for (unsigned int i = 0; i < inputFC->nb_streams; i++)
771  {
772  switch (inputFC->streams[i]->codec->codec_type)
773  {
774  case AVMEDIA_TYPE_VIDEO:
775  if (vid_id == -1)
776  vid_id = i;
777  break;
778 
779  case AVMEDIA_TYPE_AUDIO:
780  if (inputFC->streams[i]->codec->channels == 0)
781  {
782  LOG(VB_GENERAL, LOG_ERR,
783  QString("Skipping invalid audio stream: %1").arg(i));
784  break;
785  }
786  if (inputFC->streams[i]->codec->codec_id == AV_CODEC_ID_AC3 ||
787  inputFC->streams[i]->codec->codec_id == AV_CODEC_ID_MP3 ||
788  inputFC->streams[i]->codec->codec_id == AV_CODEC_ID_MP2)
789  {
790  aud_map[i] = ext_count++;
791  aFrame[i] = new FrameList();
792  }
793  else
794  LOG(VB_GENERAL, LOG_ERR,
795  QString("Skipping unsupported audio stream: %1")
796  .arg(inputFC->streams[i]->codec->codec_id));
797  break;
798  default:
799  LOG(VB_GENERAL, LOG_ERR,
800  QString("Skipping unsupported codec %1 on stream %2")
801  .arg(inputFC->streams[i]->codec->codec_type).arg(i));
802  break;
803  }
804  }
805 
806  return true;
807 }
808 
809 void MPEG2fixup::SetFrameNum(uint8_t *ptr, int num)
810 {
811  SETBITS(ptr + 4, num, 10);
812 }
813 
815 {
816  if (frame1->isSequence || !frame2->isSequence)
817  return;
818 
819  int head_size = (frame2->framePos - frame2->pkt.data);
820 
821  frame1->ensure_size(frame1->pkt.size + head_size);
822  memmove(frame1->pkt.data + head_size, frame1->pkt.data, frame1->pkt.size);
823  memcpy(frame1->pkt.data, frame2->pkt.data, head_size);
824  frame1->pkt.size += head_size;
825  ProcessVideo(frame1, header_decoder);
826 #if 0
827  if (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY))
828  {
829  static int count = 0;
830  QString filename = QString("hdr%1.yuv").arg(count++);
831  WriteFrame(filename, &frame1->pkt);
832  }
833 #endif
834 }
835 
837 {
838  int state = -1;
839  int last_pos = 0;
840  mpeg2_info_t *info;
841 
842  if (dec == header_decoder)
843  {
844  mpeg2_reset(dec, 0);
845  vf->isSequence = 0;
846  vf->isGop = 0;
847  }
848 
849  info = (mpeg2_info_t *)mpeg2_info(dec);
850 
851  mpeg2_buffer(dec, vf->pkt.data, vf->pkt.data + vf->pkt.size);
852 
853  while (state != STATE_PICTURE)
854  {
855  state = mpeg2_parse(dec);
856 
857  if (dec == header_decoder)
858  {
859  switch (state)
860  {
861 
862  case STATE_SEQUENCE:
865  memcpy(&vf->mpeg2_seq, info->sequence,
866  sizeof(mpeg2_sequence_t));
867  vf->isSequence = 1;
868  break;
869 
870  case STATE_GOP:
871  memcpy(&vf->mpeg2_gop, info->gop, sizeof(mpeg2_gop_t));
872  vf->isGop = 1;
873  vf->gopPos = vf->pkt.data + last_pos;
874  //pd->adjustFrameCount=0;
875  break;
876 
877  case STATE_PICTURE:
878  memcpy(&vf->mpeg2_pic, info->current_picture,
879  sizeof(mpeg2_picture_t));
880  vf->framePos = vf->pkt.data + last_pos;
881  break;
882 
883  case STATE_BUFFER:
884  LOG(VB_GENERAL, LOG_WARNING,
885  "Warning: partial frame found!");
886  return 1;
887  }
888  }
889  else if (state == STATE_BUFFER)
890  {
891  WriteData("abort.dat", vf->pkt.data, vf->pkt.size);
892  LOG(VB_GENERAL, LOG_ERR,
893  QString("Failed to decode frame. Position was: %1")
894  .arg(last_pos));
895  return -1;
896  }
897  last_pos = (vf->pkt.size - mpeg2_getpos(dec)) - 4;
898  }
899 
900  if (dec != header_decoder)
901  {
902  while (state != STATE_BUFFER)
903  state = mpeg2_parse(dec);
904  if (info->display_picture)
905  {
906  // This is a hack to force libmpeg2 to finish writing out the slice
907  // without it, the final row doesn't get put into the disp_pic
908  // (for B-frames only).
909  // 0xb2 is 'user data' and is actually illegal between pic
910  // headers, but it is just discarded by libmpeg2
911  uint8_t tmp[8] = {0x00, 0x00, 0x01, 0xb2, 0xff, 0xff, 0xff, 0xff};
912  mpeg2_buffer(dec, tmp, tmp + 8);
913  mpeg2_parse(dec);
914  }
915  }
916 
917  if (VERBOSE_LEVEL_CHECK(VB_DECODE, LOG_INFO))
918  {
919  QString msg = QString("");
920 #if 0
921  msg += QString("unused:%1 ") .arg(vf->pkt.size - mpeg2_getpos(dec));
922 #endif
923 
924  if (vf->isSequence)
925  msg += QString("%1x%2 P:%3 ").arg(info->sequence->width)
926  .arg(info->sequence->height).arg(info->sequence->frame_period);
927 
928  if (info->gop)
929  {
930  QString gop;
931  gop.sprintf("%02d:%02d:%02d:%03d ",
932  info->gop->hours, info->gop->minutes,
933  info->gop->seconds, info->gop->pictures);
934  msg += gop;
935  }
936  if (info->current_picture) {
937  int ct = info->current_picture->flags & PIC_MASK_CODING_TYPE;
938  char coding_type = (ct == PIC_FLAG_CODING_TYPE_I) ? 'I' :
939  ((ct == PIC_FLAG_CODING_TYPE_P) ? 'P' :
940  ((ct == PIC_FLAG_CODING_TYPE_B) ? 'B' :
941  ((ct == PIC_FLAG_CODING_TYPE_D) ?'D' : 'X')));
942  char top_bottom = (info->current_picture->flags &
943  PIC_FLAG_TOP_FIELD_FIRST) ? 'T' : 'B';
944  char progressive = (info->current_picture->flags &
945  PIC_FLAG_PROGRESSIVE_FRAME) ? 'P' : '_';
946  msg += QString("#%1 fl:%2%3%4%5%6 ")
948  .arg(info->current_picture->nb_fields)
949  .arg(coding_type)
950  .arg(top_bottom)
951  .arg(progressive)
952  .arg(info->current_picture->flags >> 4, 0, 16);
953  }
954  msg += QString("pos: %1").arg(vf->pkt.pos);
955  LOG(VB_DECODE, LOG_INFO, msg);
956  }
957 
958  return 0;
959 }
960 
961 void MPEG2fixup::WriteFrame(QString filename, MPEG2frame *f)
962 {
963  MPEG2frame *tmpFrame = GetPoolFrame(f);
964  if (tmpFrame == NULL)
965  return;
966  if (!tmpFrame->isSequence)
967  {
968  for (FrameList::Iterator it = vFrame.begin(); it != vFrame.end(); it++)
969  {
970  if ((*it)->isSequence)
971  {
972  AddSequence(tmpFrame, *it);
973  break;
974  }
975  }
976  }
977  WriteFrame(filename, &tmpFrame->pkt);
978  framePool.enqueue(tmpFrame);
979 }
980 
981 void MPEG2fixup::WriteFrame(QString filename, AVPacket *pkt)
982 {
983  MPEG2frame *tmpFrame = GetPoolFrame(pkt);
984  if (tmpFrame == NULL)
985  return;
986 
987  QString fname = filename + ".enc";
988  WriteData(fname, pkt->data, pkt->size);
989 
990  mpeg2dec_t *tmp_decoder = mpeg2_init();
991  mpeg2_info_t *info = (mpeg2_info_t *)mpeg2_info(tmp_decoder);
992 
993  while (!info->display_picture)
994  {
995  if (ProcessVideo(tmpFrame, tmp_decoder))
996  {
997  delete tmpFrame;
998  return;
999  }
1000  }
1001 
1002  WriteYUV(filename, info);
1003  framePool.enqueue(tmpFrame);
1004  mpeg2_close(tmp_decoder);
1005 }
1006 
1007 void MPEG2fixup::WriteYUV(QString filename, const mpeg2_info_t *info)
1008 {
1009  int fh = open(filename.toLocal8Bit().constData(),
1010  O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
1011  if (fh == -1) {
1012  LOG(VB_GENERAL, LOG_ERR,
1013  QString("Couldn't open file %1: ").arg(filename) + ENO);
1014  return;
1015  }
1016 
1017  int ret = write(fh, info->display_fbuf->buf[0],
1018  info->sequence->width * info->sequence->height);
1019  if (ret < 0)
1020  {
1021  LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
1022  ENO);
1023  goto closefd;
1024  }
1025  ret = write(fh, info->display_fbuf->buf[1],
1026  info->sequence->chroma_width * info->sequence->chroma_height);
1027  if (ret < 0)
1028  {
1029  LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
1030  ENO);
1031  goto closefd;
1032  }
1033  ret = write(fh, info->display_fbuf->buf[2],
1034  info->sequence->chroma_width * info->sequence->chroma_height);
1035  if (ret < 0)
1036  {
1037  LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
1038  ENO);
1039  goto closefd;
1040  }
1041 closefd:
1042  close(fh);
1043 }
1044 
1045 void MPEG2fixup::WriteData(QString filename, uint8_t *data, int size)
1046 {
1047  int fh = open(filename.toLocal8Bit().constData(),
1048  O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
1049  if (fh == -1) {
1050  LOG(VB_GENERAL, LOG_ERR,
1051  QString("Couldn't open file %1: ").arg(filename) + ENO);
1052  return;
1053  }
1054 
1055  int ret = write(fh, data, size);
1056  if (ret < 0)
1057  LOG(VB_GENERAL, LOG_ERR, QString("write failed %1").arg(filename) +
1058  ENO);
1059  close(fh);
1060 }
1061 
1062 extern "C" {
1063 #include "helper.h"
1064 }
1065 
1066 bool MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname)
1067 {
1068  const mpeg2_info_t *info;
1069  int outbuf_size;
1070  uint16_t intra_matrix[64] ATTR_ALIGN(16);
1071  AVFrame *picture;
1072  AVCodecContext *c = NULL;
1073  AVCodec *out_codec;
1074 
1075  info = mpeg2_info(img_decoder);
1076  if (!info->display_fbuf)
1077  return true;
1078 
1079  outbuf_size = info->sequence->width * info->sequence->height * 2;
1080 
1081  if (!fname.isEmpty())
1082  {
1083  QString tmpstr = fname + ".yuv";
1084  WriteYUV(tmpstr, info);
1085  }
1086 
1087  picture = avcodec_alloc_frame();
1088 
1089  pkt->data = (uint8_t *)av_malloc(outbuf_size);
1090 
1091  picture->data[0] = info->display_fbuf->buf[0];
1092  picture->data[1] = info->display_fbuf->buf[1];
1093  picture->data[2] = info->display_fbuf->buf[2];
1094 
1095  picture->linesize[0] = info->sequence->width;
1096  picture->linesize[1] = info->sequence->chroma_width;
1097  picture->linesize[2] = info->sequence->chroma_width;
1098 
1099  picture->opaque = info->display_fbuf->id;
1100 
1101  copy_quant_matrix(img_decoder, intra_matrix);
1102 
1103  if (info->display_picture->nb_fields % 2)
1104  picture->top_field_first = !(info->display_picture->flags &
1105  PIC_FLAG_TOP_FIELD_FIRST);
1106  else
1107  picture->top_field_first = !!(info->display_picture->flags &
1108  PIC_FLAG_TOP_FIELD_FIRST);
1109 
1110  picture->interlaced_frame = !(info->display_picture->flags &
1111  PIC_FLAG_PROGRESSIVE_FRAME);
1112 
1113  out_codec = avcodec_find_encoder(AV_CODEC_ID_MPEG2VIDEO);
1114 
1115  if (!out_codec)
1116  {
1117  free(picture);
1118  LOG(VB_GENERAL, LOG_ERR, "Couldn't find MPEG2 encoder");
1119  return true;
1120  }
1121 
1122  c = avcodec_alloc_context3(NULL);
1123 
1124  //NOTE: The following may seem wrong, but avcodec requires
1125  //sequence->progressive == frame->progressive
1126  //We fix the discrepancy by discarding avcodec's sequence header, and
1127  //replace it with the original
1128  if (picture->interlaced_frame)
1129  c->flags |= CODEC_FLAG_INTERLACED_DCT;
1130 
1131  c->bit_rate = info->sequence->byte_rate << 3; //not used
1132  c->bit_rate_tolerance = c->bit_rate >> 2; //not used
1133  c->width = info->sequence->width;
1134  c->height = info->sequence->height;
1135  av_reduce(&c->time_base.num, &c->time_base.den,
1136  info->sequence->frame_period, 27000000LL, 100000);
1137  c->pix_fmt = PIX_FMT_YUV420P;
1138  c->max_b_frames = 0;
1139  c->has_b_frames = 0;
1140  c->rc_buffer_aggressivity = 1;
1141  // c->profile = vidCC->profile;
1142  // c->level = vidCC->level;
1143  c->rc_buffer_size = 0;
1144  c->gop_size = 0; // this should force all i-frames
1145  // c->flags=CODEC_FLAG_LOW_DELAY;
1146 
1147  if (intra_matrix[0] == 0x08)
1148  c->intra_matrix = intra_matrix;
1149 
1150  c->qmin = c->qmax = 2;
1151 
1152  picture->pts = AV_NOPTS_VALUE;
1153  picture->key_frame = 1;
1154  picture->pict_type = AV_PICTURE_TYPE_NONE;
1155  picture->type = 0;
1156  picture->quality = 0;
1157 
1158  if (avcodec_open2(c, out_codec, NULL) < 0)
1159  {
1160  free(picture);
1161  LOG(VB_GENERAL, LOG_ERR, "could not open codec");
1162  return true;
1163  }
1164 
1165  int got_packet = 0;
1166  int ret;
1167  bool initial = true;
1168 
1169  // Need to call this repeatedly as it seems to be pipelined. The first
1170  // call will return no packet, then the second one will flush it. In case
1171  // it becomes more pipelined, just loop until it creates a packet or errors
1172  // out.
1173  while (!got_packet)
1174  {
1175  ret = avcodec_encode_video2(c, pkt, (initial ? picture : NULL),
1176  &got_packet);
1177 
1178  if (ret < 0)
1179  {
1180  free(picture);
1181  LOG(VB_GENERAL, LOG_ERR,
1182  QString("avcodec_encode_video2 failed (%1)").arg(ret));
1183  return true;
1184  }
1185  }
1186 
1187  if (!fname.isEmpty())
1188  {
1189  QString ename = fname + ".enc";
1190  WriteData(ename, pkt->data, pkt->size);
1191 
1192  QString yname = fname + ".enc.yuv";
1193  WriteFrame(yname, pkt);
1194  }
1195  int delta = FindMPEG2Header(pkt->data, pkt->size, 0x00);
1196  // out_size=avcodec_encode_video(c, outbuf, outbuf_size, picture);
1197  pkt->size -= delta; // a hack to get to the picture frame
1198  memmove(pkt->data, pkt->data + delta, pkt->size);
1199  SetRepeat(pkt->data, pkt->size, info->display_picture->nb_fields,
1200  !!(info->display_picture->flags & PIC_FLAG_TOP_FIELD_FIRST));
1201 
1202  avcodec_close(c);
1203  av_freep(&c);
1204  av_freep(&picture);
1205 
1206  return false;
1207 }
1208 
1209 #define MAX_FRAMES 20000
1211 {
1212  MPEG2frame *f;
1213  static int frame_count = 0;
1214 
1215  if (framePool.isEmpty())
1216  {
1217  if (frame_count >= MAX_FRAMES)
1218  {
1219  LOG(VB_GENERAL, LOG_ERR, "No more queue slots!");
1220  return NULL;
1221  }
1222  f = new MPEG2frame(pkt->size);
1223  frame_count++;
1224  }
1225  else
1226  f = framePool.dequeue();
1227 
1228  f->set_pkt(pkt);
1229 
1230  return f;
1231 }
1232 
1234 {
1235  MPEG2frame *tmpFrame = GetPoolFrame(&f->pkt);
1236  if (!tmpFrame)
1237  return tmpFrame;
1238 
1239  tmpFrame->isSequence = f->isSequence;
1240  tmpFrame->isGop = f->isGop;
1241  tmpFrame->mpeg2_seq = f->mpeg2_seq;
1242  tmpFrame->mpeg2_gop = f->mpeg2_gop;
1243  tmpFrame->mpeg2_pic = f->mpeg2_pic;
1244  return tmpFrame;
1245 }
1246 
1247 int MPEG2fixup::GetFrame(AVPacket *pkt)
1248 {
1249  int ret;
1250 
1251  while (true)
1252  {
1253  bool done = false;
1254  if (unreadFrames.count())
1255  {
1256  vFrame.append(unreadFrames.dequeue());
1257  if (real_file_end && !unreadFrames.count())
1258  file_end = true;
1259  return file_end;
1260  }
1261 
1262  while (!done)
1263  {
1264  pkt->pts = AV_NOPTS_VALUE;
1265  pkt->dts = AV_NOPTS_VALUE;
1266  ret = av_read_frame(inputFC, pkt);
1267 
1268  if (ret < 0)
1269  {
1270  // If it is EAGAIN, obey it, dangit!
1271  if (ret == -EAGAIN)
1272  continue;
1273 
1274  //insert a bogus frame (this won't be written out)
1275  if (vFrame.isEmpty())
1276  {
1277  LOG(VB_GENERAL, LOG_ERR,
1278  "Found end of file without finding any frames");
1279  av_free_packet(pkt);
1280  return 1;
1281  }
1282 
1283  MPEG2frame *tmpFrame = GetPoolFrame(&vFrame.last()->pkt);
1284  if (tmpFrame == NULL)
1285  {
1286  av_free_packet(pkt);
1287  return 1;
1288  }
1289 
1290  vFrame.append(tmpFrame);
1291  real_file_end = true;
1292  file_end = true;
1293  return 1;
1294  }
1295 
1296  if (pkt->stream_index == vid_id ||
1297  aFrame.contains(pkt->stream_index))
1298  done = true;
1299  else
1300  av_free_packet(pkt);
1301  }
1302  pkt->duration = framenum++;
1303  if ((showprogress || update_status) &&
1305  {
1306  float percent_done = 100.0 * pkt->pos / filesize;
1307  if (update_status)
1308  update_status(percent_done);
1309  if (showprogress)
1310  LOG(VB_GENERAL, LOG_INFO, QString("%1% complete")
1311  .arg(percent_done, 0, 'f', 1));
1312  if (check_abort && check_abort())
1313  return REENCODE_STOPPED;
1316  }
1317 
1318 #ifdef DEBUG_AUDIO
1319  LOG(VB_DECODE, LOG_INFO, QString("Stream: %1 PTS: %2 DTS: %3 pos: %4")
1320  .arg(pkt->stream_index)
1321  .arg((pkt->pts == AV_NOPTS_VALUE) ? "NONE" : PtsTime(pkt->pts))
1322  .arg((pkt->dts == AV_NOPTS_VALUE) ? "NONE" : PtsTime(pkt->dts))
1323  .arg(pkt->pos));
1324 #endif
1325 
1326  MPEG2frame *tmpFrame = GetPoolFrame(pkt);
1327  if (tmpFrame == NULL)
1328  {
1329  av_free_packet(pkt);
1330  return 1;
1331  }
1332 
1333  switch (inputFC->streams[pkt->stream_index]->codec->codec_type)
1334  {
1335  case AVMEDIA_TYPE_VIDEO:
1336  vFrame.append(tmpFrame);
1337  av_free_packet(pkt);
1338 
1339  if (!ProcessVideo(vFrame.last(), header_decoder))
1340  return 0;
1341  framePool.enqueue(vFrame.takeLast());
1342  break;
1343 
1344  case AVMEDIA_TYPE_AUDIO:
1345  aFrame[pkt->stream_index]->append(tmpFrame);
1346  av_free_packet(pkt);
1347  return 0;
1348 
1349  default:
1350  framePool.enqueue(tmpFrame);
1351  av_free_packet(pkt);
1352  return 1;
1353  }
1354  }
1355 }
1356 
1358 {
1359  AVPacket pkt;
1360  QMap <int, bool> found;
1361 
1362  av_init_packet(&pkt);
1363 
1364  do
1365  {
1366  if (GetFrame(&pkt))
1367  return false;
1368 
1369  if (vid_id == pkt.stream_index)
1370  {
1371  while (!vFrame.isEmpty())
1372  {
1373  if (vFrame.first()->isSequence)
1374  {
1375  if (pkt.pos != vFrame.first()->pkt.pos)
1376  break;
1377 
1378  if (pkt.pts != AV_NOPTS_VALUE ||
1379  pkt.dts != AV_NOPTS_VALUE)
1380  {
1381  if (pkt.pts == AV_NOPTS_VALUE)
1382  vFrame.first()->pkt.pts = pkt.dts;
1383 
1384  LOG(VB_PROCESS, LOG_INFO,
1385  "Found 1st valid video frame");
1386  break;
1387  }
1388  }
1389 
1390  LOG(VB_PROCESS, LOG_INFO, "Dropping V packet");
1391 
1392  framePool.enqueue(vFrame.takeFirst());
1393  }
1394  }
1395 
1396  if (vFrame.isEmpty())
1397  continue;
1398 
1399  for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
1400  {
1401  if (found.contains(it.key()))
1402  continue;
1403 
1404  FrameList *af = (*it);
1405 
1406  while (!af->isEmpty())
1407  {
1408  int64_t delta = diff2x33(af->first()->pkt.pts,
1409  vFrame.first()->pkt.pts);
1410  if (delta < -180000 || delta > 180000) //2 seconds
1411  {
1412  //Check all video sequence packets against current
1413  //audio packet
1414  MPEG2frame *foundframe = NULL;
1415  for (FrameList::Iterator it2 = vFrame.begin();
1416  it2 != vFrame.end(); it2++)
1417  {
1418  MPEG2frame *currFrame = (*it2);
1419  if (currFrame->isSequence)
1420  {
1421  int64_t dlta1 = diff2x33(af->first()->pkt.pts,
1422  currFrame->pkt.pts);
1423  if (dlta1 >= -180000 && dlta1 <= 180000)
1424  {
1425  foundframe = currFrame;
1426  delta = dlta1;
1427  break;
1428  }
1429  }
1430  }
1431 
1432  while (foundframe && vFrame.first() != foundframe)
1433  {
1434  framePool.enqueue(vFrame.takeFirst());
1435  }
1436  }
1437 
1438  if (delta < -180000 || delta > 180000) //2 seconds
1439  {
1440  LOG(VB_PROCESS, LOG_INFO,
1441  QString("Dropping A packet from stream %1")
1442  .arg(it.key()));
1443  LOG(VB_PROCESS, LOG_INFO, QString(" A:%1 V:%2")
1444  .arg(PtsTime(af->first()->pkt.pts))
1445  .arg(PtsTime(vFrame.first()->pkt.pts)));
1446  framePool.enqueue(af->takeFirst());
1447  continue;
1448  }
1449 
1450  if (delta < 0 && af->count() > 1)
1451  {
1452  if (cmp2x33(af->at(1)->pkt.pts,
1453  vFrame.first()->pkt.pts) > 0)
1454  {
1455  LOG(VB_PROCESS, LOG_INFO,
1456  QString("Found useful audio frame from stream %1")
1457  .arg(it.key()));
1458  found[it.key()] = 1;
1459  break;
1460  }
1461  else
1462  {
1463  LOG(VB_PROCESS, LOG_INFO,
1464  QString("Dropping A packet from stream %1")
1465  .arg(it.key()));
1466  framePool.enqueue(af->takeFirst());
1467  continue;
1468  }
1469  }
1470  else if (delta >= 0)
1471  {
1472  LOG(VB_PROCESS, LOG_INFO,
1473  QString("Found useful audio frame from stream %1")
1474  .arg(it.key()));
1475  found[it.key()] = 1;
1476  break;
1477  }
1478 
1479  if (af->count() == 1)
1480  break;
1481  }
1482  }
1483  } while (found.count() != aFrame.count());
1484 
1485  return true;
1486 }
1487 
1488 void MPEG2fixup::SetRepeat(MPEG2frame *vf, int fields, bool topff)
1489 {
1490  vf->mpeg2_pic.nb_fields = 2;
1491  SetRepeat(vf->framePos, vf->pkt.data + vf->pkt.size - vf->framePos,
1492  fields, topff);
1493 }
1494 
1495 void MPEG2fixup::SetRepeat(uint8_t *ptr, int size, int fields, bool topff)
1496 {
1497  uint8_t *end = ptr + size;
1498  uint8_t setmask = 0x00;
1499  uint8_t clrmask = 0xff;
1500  if (topff)
1501  setmask |= 0x80;
1502  else
1503  clrmask &= 0x7f;
1504 
1505  if (fields == 2)
1506  clrmask &= 0xfd;
1507  else
1508  setmask |= 0x02;
1509 
1510  while (ptr < end)
1511  {
1512  if (MATCH_HEADER(ptr) && ptr[3] == 0xB5 && (ptr[4] & 0xF0) == 0x80)
1513  {
1514  //unset repeat_first_field
1515  //set top_field_first
1516  ptr[7] |= setmask;
1517  ptr[7] &= clrmask;
1518  return;
1519  }
1520 
1521  ptr++;
1522  }
1523 }
1524 
1526 {
1527  for (FrameList::Iterator it = vFrame.begin(); it != vFrame.end(); it++)
1528  {
1529  if (GetFrameNum((*it)) == frameNum)
1530  return (*it);
1531  }
1532 
1533  return NULL;
1534 }
1535 
1536 void MPEG2fixup::RenumberFrames(int start_pos, int delta)
1537 {
1538  int maxPos = vFrame.count() - 1;
1539 
1540  for (int pos = start_pos; pos < maxPos; pos++)
1541  {
1542  MPEG2frame *frame = vFrame.at(pos);
1543  SetFrameNum(frame->framePos, GetFrameNum(frame) + delta);
1544  frame->mpeg2_pic.temporal_reference += delta;
1545  }
1546 }
1547 
1549 {
1550  while (vSecondary.count())
1551  {
1552  framePool.enqueue(vSecondary.takeFirst());
1553  }
1554 
1555  while (vFrame.count() > 1)
1556  {
1557  if (use_secondary && GetFrameTypeT(vFrame.first()) != 'B')
1558  vSecondary.append(vFrame.takeFirst());
1559  else
1560  framePool.enqueue(vFrame.takeFirst());
1561  }
1562 }
1563 
1565 {
1566  int frame_num = 0;
1568  for (FrameList::Iterator it = vSecondary.begin(); it != vSecondary.end();
1569  it++)
1570  {
1571  SetFrameNum((*it)->framePos, frame_num++);
1572  if (ProcessVideo((*it), img_decoder) < 0)
1573  return 1;
1574  }
1575  return 0;
1576 }
1577 
1578 MPEG2frame *MPEG2fixup::DecodeToFrame(int frameNum, int skip_reset)
1579 {
1580  MPEG2frame *spare = NULL;
1581  int found = 0;
1582  bool skip_first = false;
1583  const mpeg2_info_t * info = mpeg2_info(img_decoder);
1584  int maxPos = vFrame.count() - 1;
1585 
1586  if (vFrame.at(displayFrame)->isSequence)
1587  {
1588  skip_first = true;
1589  if (!skip_reset && (displayFrame != maxPos || displayFrame == 0))
1591  }
1592 
1593  spare = FindFrameNum(frameNum);
1594  if (!spare)
1595  return NULL;
1596 
1597  int framePos = vFrame.indexOf(spare);
1598 
1599  for (int curPos = displayFrame; displayFrame != maxPos;
1600  curPos++, displayFrame++)
1601  {
1603  return NULL;
1604 
1605  if (!skip_first && curPos >= framePos && info->display_picture &&
1606  (int)info->display_picture->temporal_reference >= frameNum)
1607  {
1608  found = 1;
1609  displayFrame++;
1610  break;
1611  }
1612 
1613  skip_first = false;
1614  }
1615 
1616  if (!found)
1617  {
1618  int tmpFrameNum = frameNum;
1619  MPEG2frame *tmpFrame = GetPoolFrame(&spare->pkt);
1620  if (tmpFrame == NULL)
1621  return NULL;
1622 
1623  tmpFrame->framePos = tmpFrame->pkt.data +
1624  (spare->framePos - spare->pkt.data);
1625 
1626  while (!info->display_picture ||
1627  (int)info->display_picture->temporal_reference < frameNum)
1628  {
1629  SetFrameNum(tmpFrame->framePos, ++tmpFrameNum);
1630  if (ProcessVideo(tmpFrame, img_decoder) < 0)
1631  {
1632  delete tmpFrame;
1633  return NULL;
1634  }
1635  }
1636 
1637  framePool.enqueue(tmpFrame);
1638  }
1639 
1640  if ((int)info->display_picture->temporal_reference > frameNum)
1641  {
1642  // the frame in question doesn't exist. We have no idea where we are.
1643  // reset the displayFrame so we start searching from the beginning next
1644  // time
1645  displayFrame = 0;
1646  LOG(VB_GENERAL, LOG_NOTICE,
1647  QString("Frame %1 > %2. Corruption likely at pos: %3")
1648  .arg(info->display_picture->temporal_reference)
1649  .arg(frameNum).arg(spare->pkt.pos));
1650  }
1651 
1652  return spare;
1653 }
1654 
1655 int MPEG2fixup::ConvertToI(FrameList *orderedFrames, int headPos)
1656 {
1657  MPEG2frame *spare = NULL;
1658  AVPacket pkt;
1659 #ifdef SPEW_FILES
1660  static int ins_count = 0;
1661 #endif
1662 
1663  //head_pos == 0 means that we are decoding B frames after a seq_header
1664  if (headPos == 0)
1665  if (PlaybackSecondary())
1666  return 1;
1667 
1668  for (FrameList::Iterator it = orderedFrames->begin();
1669  it != orderedFrames->end(); it++)
1670  {
1671  int i = GetFrameNum((*it));
1672  if ((spare = DecodeToFrame(i, headPos == 0)) == NULL)
1673  {
1674  LOG(VB_GENERAL, LOG_WARNING,
1675  QString("ConvertToI skipping undecoded frame #%1").arg(i));
1676  continue;
1677  }
1678 
1679  if (GetFrameTypeT(spare) == 'I')
1680  continue;
1681 
1682  pkt = spare->pkt;
1683  //pkt.data is a newly malloced area
1684 
1685  {
1686  QString fname;
1687 
1688 #ifdef SPEW_FILES
1689  if (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY))
1690  fname = QString("cnv%1").arg(ins_count++);
1691 #endif
1692 
1693  if (BuildFrame(&pkt, fname))
1694  return 1;
1695 
1696  LOG(VB_GENERAL, LOG_INFO,
1697  QString("Converting frame #%1 from %2 to I %3")
1698  .arg(i).arg(GetFrameTypeT(spare)).arg(fname));
1699  }
1700 
1701  spare->set_pkt(&pkt);
1702  av_free(pkt.data);
1703  SetFrameNum(spare->pkt.data, GetFrameNum(spare));
1704  ProcessVideo(spare, header_decoder); //process this new frame
1705  }
1706 
1707  //reorder frames
1708  vFrame.move(headPos, headPos + orderedFrames->count() - 1);
1709  return 0;
1710 }
1711 
1712 int MPEG2fixup::InsertFrame(int frameNum, int64_t deltaPTS,
1713  int64_t ptsIncrement, int64_t initPTS)
1714 {
1715  MPEG2frame *spare = NULL;
1716  AVPacket pkt;
1717  int increment = 0;
1718  int index = 0;
1719 #ifdef SPEW_FILES
1720  static int ins_count = 0;
1721 #endif
1722 
1723  if ((spare = DecodeToFrame(frameNum, 0)) == NULL)
1724  return -1;
1725 
1726  pkt = spare->pkt;
1727  //pkt.data is a newly malloced area
1728 
1729  {
1730  QString fname;
1731 #if SPEW_FILES
1732  fname = (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY) ?
1733  (QString("ins%1").arg(ins_count++)) : QString());
1734 #endif
1735 
1736  if (BuildFrame(&pkt, fname))
1737  return -1;
1738 
1739  LOG(VB_GENERAL, LOG_INFO,
1740  QString("Inserting %1 I-Frames after #%2 %3")
1741  .arg((int)(deltaPTS / ptsIncrement))
1742  .arg(GetFrameNum(spare)).arg(fname));
1743  }
1744 
1745  inc2x33(&pkt.pts, ptsIncrement * GetNbFields(spare) / 2 + initPTS);
1746 
1747  index = vFrame.indexOf(spare) + 1;
1748  while (index < vFrame.count() &&
1749  GetFrameTypeT(vFrame.at(index)) == 'B')
1750  spare = vFrame.at(index++);
1751 
1752  index = vFrame.indexOf(spare);
1753 
1754  while (deltaPTS > 0)
1755  {
1756  MPEG2frame *tmpFrame;
1757  index++;
1758  increment++;
1759  pkt.dts = pkt.pts;
1760  SetFrameNum(pkt.data, ++frameNum);
1761  tmpFrame = GetPoolFrame(&pkt);
1762  if (tmpFrame == NULL)
1763  return -1;
1764  vFrame.insert(index, tmpFrame);
1765  ProcessVideo(tmpFrame, header_decoder); //process new frame
1766 
1767  inc2x33(&pkt.pts, ptsIncrement);
1768  deltaPTS -= ptsIncrement;
1769  }
1770 
1771  av_free(pkt.data);
1772 
1773  // update frame # for all later frames in this group
1774  index++;
1775  RenumberFrames(index, increment);
1776 
1777  return increment;
1778 }
1779 
1780 void MPEG2fixup::AddRangeList(QStringList rangelist, int type)
1781 {
1782  QStringList::iterator i;
1783  frm_dir_map_t *mapPtr;
1784 
1785  if (type == MPF_TYPE_CUTLIST)
1786  {
1787  mapPtr = &delMap;
1788  discard = 0;
1789  }
1790  else
1791  mapPtr = &saveMap;
1792 
1793  mapPtr->clear();
1794 
1795  for (i = rangelist.begin(); i != rangelist.end(); ++i)
1796  {
1797  QStringList tmp = (*i).split(" - ");
1798  if (tmp.size() < 2)
1799  continue;
1800 
1801  bool ok[2] = { false, false };
1802 
1803  long long start = tmp[0].toLongLong(&ok[0]);
1804  long long end = tmp[1].toLongLong(&ok[1]);
1805 
1806  if (ok[0] && ok[1])
1807  {
1808  if (start == 0)
1809  {
1810  if (type == MPF_TYPE_CUTLIST)
1811  discard = 1;
1812  }
1813  else
1814  mapPtr->insert(start - 1, MARK_CUT_START);
1815 
1816  mapPtr->insert(end, MARK_CUT_END);
1817  }
1818  }
1819 
1820  if (rangelist.count())
1821  use_secondary = true;
1822 }
1823 
1824 void MPEG2fixup::ShowRangeMap(frm_dir_map_t *mapPtr, QString msg)
1825 {
1826  if (mapPtr->count())
1827  {
1828  int64_t start = 0;
1829  frm_dir_map_t::iterator it = mapPtr->begin();
1830  for (; it != mapPtr->end(); ++it)
1831  if (*it == 0)
1832  msg += QString("\n\t\t%1 - %2").arg(start).arg(it.key());
1833  else
1834  start = it.key();
1835  LOG(VB_PROCESS, LOG_INFO, msg);
1836  }
1837 }
1838 
1840 {
1841  FrameList Lreorder;
1842  int maxPos = dtsOrder->count() - 1;
1843 
1844  if (pos >= maxPos)
1845  return Lreorder;
1846 
1847  MPEG2frame *frame = dtsOrder->at(pos);
1848 
1849  for (pos++; pos < maxPos && GetFrameTypeT(dtsOrder->at(pos)) == 'B'; pos++)
1850  Lreorder.append(dtsOrder->at(pos));
1851 
1852  Lreorder.append(frame);
1853  return Lreorder;
1854 }
1855 
1856 void MPEG2fixup::InitialPTSFixup(MPEG2frame *curFrame, int64_t &origvPTS,
1857  int64_t &PTSdiscrep, int numframes, bool fix)
1858 {
1859  int64_t tmpPTS = diff2x33(curFrame->pkt.pts,
1860  origvPTS / 300);
1861 
1862  if (curFrame->pkt.pts == AV_NOPTS_VALUE)
1863  {
1864  LOG(VB_PROCESS, LOG_INFO,
1865  QString("Found frame %1 with missing PTS at %2")
1866  .arg(GetFrameNum(curFrame))
1867  .arg(PtsTime(origvPTS / 300)));
1868  if (fix)
1869  curFrame->pkt.pts = origvPTS / 300;
1870  else
1871  PTSdiscrep = AV_NOPTS_VALUE;
1872  }
1873  else if (tmpPTS < -ptsIncrement ||
1874  tmpPTS > ptsIncrement*numframes)
1875  {
1876  if (tmpPTS != PTSdiscrep)
1877  {
1878  PTSdiscrep = tmpPTS;
1879  LOG(VB_PROCESS, LOG_INFO,
1880  QString("Found invalid PTS (off by %1) at %2")
1881  .arg(PtsTime(tmpPTS))
1882  .arg(PtsTime(origvPTS / 300)));
1883  }
1884  if (fix)
1885  curFrame->pkt.pts = origvPTS / 300;
1886  }
1887  else
1888  {
1889  origvPTS = curFrame->pkt.pts * 300;
1890  }
1891  ptsinc((uint64_t *)&origvPTS,
1892  (uint64_t)(150 * ptsIncrement * GetNbFields(curFrame)));
1893 }
1894 
1896 {
1897  LOG(VB_GENERAL, LOG_INFO, "=========================================");
1898  LOG(VB_GENERAL, LOG_INFO, QString("List contains %1 items")
1899  .arg(list->count()));
1900 
1901  for (FrameList::Iterator it = list->begin(); it != list->end(); it++)
1902  {
1903  MPEG2frame *curFrame = (*it);
1904 
1905  LOG(VB_GENERAL, LOG_INFO,
1906  QString("VID: %1 #:%2 nb: %3 pts: %4 dts: %5 pos: %6")
1907  .arg(GetFrameTypeT(curFrame))
1908  .arg(GetFrameNum(curFrame))
1909  .arg(GetNbFields(curFrame))
1910  .arg(PtsTime(curFrame->pkt.pts))
1911  .arg(PtsTime(curFrame->pkt.dts))
1912  .arg(curFrame->pkt.pos));
1913  }
1914  LOG(VB_GENERAL, LOG_INFO, "=========================================");
1915 }
1916 
1918 {
1919  // NOTE: expectedvPTS/DTS are in units of SCR (300*PTS) to allow for better
1920  // accounting of rounding errors (still won't be right, but better)
1921  int64_t expectedvPTS; // , expectedPTS[N_AUDIO];
1922  int64_t expectedDTS = 0, lastPTS = 0, initPTS = 0, deltaPTS = 0;
1923  int64_t origvPTS = 0, origaPTS[N_AUDIO];
1924  int64_t cutStartPTS = 0, cutEndPTS = 0;
1925  uint64_t frame_count = 0;
1926  int new_discard_state = 0;
1927  int ret;
1928  QMap<int, int> af_dlta_cnt, cutState;
1929 
1930  AVPacket pkt, lastRealvPkt;
1931 
1932  if (!InitAV(infile, format, 0))
1933  return GENERIC_EXIT_NOT_OK;
1934 
1935  if (!FindStart())
1936  return GENERIC_EXIT_NOT_OK;
1937 
1938  av_init_packet(&pkt);
1939 
1940  ptsIncrement = vFrame.first()->mpeg2_seq.frame_period / 300;
1941 
1942  initPTS = vFrame.first()->pkt.pts;
1943 
1944  LOG(VB_GENERAL, LOG_INFO, QString("#%1 PTS:%2 Delta: 0.0ms queue: %3")
1945  .arg(vid_id).arg(PtsTime(vFrame.first()->pkt.pts))
1946  .arg(vFrame.count()));
1947 
1948  for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
1949  {
1950  FrameList *af = (*it);
1951  deltaPTS = diff2x33(vFrame.first()->pkt.pts, af->first()->pkt.pts);
1952  LOG(VB_GENERAL, LOG_INFO,
1953  QString("#%1 PTS:%2 Delta: %3ms queue: %4")
1954  .arg(it.key()) .arg(PtsTime(af->first()->pkt.pts))
1955  .arg(1000.0*deltaPTS / 90000.0).arg(af->count()));
1956 
1957  if (cmp2x33(af->first()->pkt.pts, initPTS) < 0)
1958  initPTS = af->first()->pkt.pts;
1959  }
1960 
1961  initPTS -= 16200; //0.18 seconds back to prevent underflow
1962 
1963  PTSOffsetQueue poq(vid_id, aFrame.keys(), initPTS);
1964 
1965  LOG(VB_PROCESS, LOG_INFO,
1966  QString("ptsIncrement: %1 Frame #: %2 PTS-adjust: %3")
1967  .arg(ptsIncrement).arg(GetFrameNum(vFrame.first()))
1968  .arg(PtsTime(initPTS)));
1969 
1970 
1971  origvPTS = 300 * udiff2x33(vFrame.first()->pkt.pts,
1972  ptsIncrement * GetFrameNum(vFrame.first()));
1973  expectedvPTS = 300 * (udiff2x33(vFrame.first()->pkt.pts, initPTS) -
1974  (ptsIncrement * GetFrameNum(vFrame.first())));
1975  expectedDTS = expectedvPTS - 300 * ptsIncrement;
1976 
1977  if (discard)
1978  {
1979  cutStartPTS = origvPTS / 300;
1980  }
1981 
1982  for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
1983  {
1984  FrameList *af = (*it);
1985  origaPTS[it.key()] = af->first()->pkt.pts * 300;
1986  //expectedPTS[it.key()] = udiff2x33(af->first()->pkt.pts, initPTS);
1987  af_dlta_cnt[it.key()] = 0;
1988  cutState[it.key()] = !!(discard);
1989  }
1990 
1991  ShowRangeMap(&delMap, "Cutlist:");
1992  ShowRangeMap(&saveMap, "Same Range:");
1993 
1994  InitReplex();
1995 
1996  while (!file_end)
1997  {
1998  /* read packet */
1999  if ((ret = GetFrame(&pkt)) < 0)
2000  return ret;
2001 
2002  if (vFrame.count() && (file_end || vFrame.last()->isSequence))
2003  {
2004  displayFrame = 0;
2005 
2006  // since we might reorder the frames when coming out of a cutpoint
2007  // me need to save the first frame here, as it is guaranteed to
2008  // have a sequence header.
2009  MPEG2frame *seqFrame = vFrame.first();
2010 
2011  if (!seqFrame->isSequence)
2012  {
2013  LOG(VB_GENERAL, LOG_WARNING,
2014  QString("Problem: Frame %1 (type %2) doesn't contain "
2015  "sequence header!")
2016  .arg(frame_count) .arg(GetFrameTypeT(seqFrame)));
2017  }
2018 
2019  if (ptsIncrement != seqFrame->mpeg2_seq.frame_period / 300)
2020  {
2021  LOG(VB_GENERAL, LOG_WARNING,
2022  QString("WARNING - Unsupported FPS change from %1 to %2")
2023  .arg(90000.0 / ptsIncrement, 0, 'f', 2)
2024  .arg(27000000.0 / seqFrame->mpeg2_seq.frame_period,
2025  0, 'f', 2));
2026  }
2027 
2028  for (int frame_pos = 0; frame_pos < vFrame.count() - 1;)
2029  {
2030  bool ptsorder_eq_dtsorder = false;
2031  int64_t dtsExtra = 0, PTSdiscrep = 0;
2032  FrameList Lreorder;
2033  MPEG2frame *markedFrame = NULL, *markedFrameP = NULL;
2034 
2035  if (expectedvPTS != expectedDTS + ptsIncrement * 300)
2036  {
2037  LOG(VB_GENERAL, LOG_ERR,
2038  QString("expectedPTS != expectedDTS + ptsIncrement"));
2039  LOG(VB_GENERAL, LOG_ERR, QString("%1 != %2 + %3")
2040  .arg(PtsTime(expectedvPTS / 300))
2041  .arg(PtsTime(expectedDTS / 300))
2042  .arg(PtsTime(ptsIncrement)));
2043  LOG(VB_GENERAL, LOG_ERR, QString("%1 != %2 + %3")
2044  .arg(expectedvPTS)
2045  .arg(expectedDTS)
2046  .arg(ptsIncrement));
2047  return GENERIC_EXIT_NOT_OK;
2048  }
2049 
2050  //reorder frames in presentation order (to the next I/P frame)
2051  Lreorder = ReorderDTStoPTS(&vFrame, frame_pos);
2052 
2053  //First pass at fixing PTS values (fixes gross errors only)
2054  for (FrameList::Iterator it2 = Lreorder.begin();
2055  it2 != Lreorder.end(); it2++)
2056  {
2057  MPEG2frame *curFrame = (*it2);
2058  poq.UpdateOrigPTS(vid_id, origvPTS, curFrame->pkt);
2059  InitialPTSFixup(curFrame, origvPTS, PTSdiscrep,
2060  maxframes, true);
2061  }
2062 
2063  // if there was a PTS jump, find the largest change
2064  // in the next x frames
2065  // At the end of this, vFrame should look just like it did
2066  // beforehand
2067  if (PTSdiscrep && !file_end)
2068  {
2069  int pos = vFrame.count();
2070  int count = Lreorder.count();
2071  while (vFrame.count() - frame_pos - count < 20 && !file_end)
2072  if ((ret = GetFrame(&pkt)) < 0)
2073  return ret;
2074 
2075  if (!file_end)
2076  {
2077  int64_t tmp_origvPTS = origvPTS;
2078  int numframes = (maxframes > 1) ? maxframes - 1 : 1;
2079  bool done = false;
2080  while (!done &&
2081  (frame_pos + count + 1) < vFrame.count())
2082  {
2083  FrameList tmpReorder;
2084  tmpReorder = ReorderDTStoPTS(&vFrame,
2085  frame_pos + count);
2086  for (FrameList::Iterator it2 = tmpReorder.begin();
2087  it2 != tmpReorder.end(); it2++)
2088  {
2089  MPEG2frame *curFrame = (*it2);
2090  int64_t tmpPTSdiscrep = 0;
2091  InitialPTSFixup(curFrame, tmp_origvPTS,
2092  tmpPTSdiscrep, numframes, false);
2093  if (!tmpPTSdiscrep)
2094  {
2095  //discrepancy was short-lived, continue on
2096  done = true;
2097  PTSdiscrep = 0;
2098  break;
2099  }
2100  if (tmpPTSdiscrep != AV_NOPTS_VALUE &&
2101  tmpPTSdiscrep != PTSdiscrep)
2102  PTSdiscrep = tmpPTSdiscrep;
2103  }
2104  count += tmpReorder.count();
2105  }
2106  }
2107 
2108  // push extra read frames onto 'unreadFrames' queue
2109  while (vFrame.count() > pos)
2110  {
2111  unreadFrames.enqueue(vFrame.takeAt(pos));
2112  }
2113  file_end = false;
2114  }
2115 
2116  //check for cutpoints and convert to I-frames if needed
2117  for (int curIndex = 0; curIndex < Lreorder.count(); curIndex++)
2118  {
2119  MPEG2frame *curFrame = Lreorder.at(curIndex);
2120  if (saveMap.count())
2121  {
2122  if (saveMap.begin().key() <= frame_count)
2123  saveMap.remove(saveMap.begin().key());
2124  if (saveMap.count() && saveMap.begin().value() == 0)
2125  {
2126  LOG(VB_GENERAL, LOG_INFO,
2127  QString("Saving frame #%1") .arg(frame_count));
2128 
2129  if (GetFrameTypeT(curFrame) != 'I' &&
2130  ConvertToI(&Lreorder, frame_pos))
2131  {
2132  return GENERIC_EXIT_WRITE_FRAME_ERROR;
2133  }
2134 
2135  WriteFrame(QString("save%1.yuv").arg(frame_count),
2136  curFrame);
2137  }
2138  }
2139 
2140  if (delMap.count() && delMap.begin().key() <= frame_count)
2141  {
2142  new_discard_state = delMap.begin().value();
2143  LOG(VB_GENERAL, LOG_INFO,
2144  QString("Del map found %1 at %2 (%3)")
2145  .arg(new_discard_state) .arg(frame_count)
2146  .arg(delMap.begin().key()));
2147 
2148  delMap.remove(delMap.begin().key());
2149  markedFrameP = curFrame;
2150 
2151  if (!new_discard_state)
2152  {
2153  cutEndPTS = markedFrameP->pkt.pts;
2154  poq.SetNextPTS(
2155  diff2x33(cutEndPTS, expectedvPTS / 300),
2156  cutEndPTS);
2157  }
2158  else
2159  {
2160  cutStartPTS =
2161  add2x33(markedFrameP->pkt.pts,
2162  ptsIncrement *
2163  GetNbFields(markedFrameP) / 2);
2164  for (FrameMap::Iterator it3 = aFrame.begin();
2165  it3 != aFrame.end(); it3++)
2166  {
2167  cutState[it3.key()] = 1;
2168  }
2169  }
2170 
2171  // Rebuild when 'B' frame, or completing a cut, and the
2172  // marked frame is a 'P' frame.
2173  // After conversion, frames will be in linear order.
2174  if ((GetFrameTypeT(curFrame) == 'B') ||
2175  (!new_discard_state &&
2176  (GetFrameTypeT(curFrame) == 'P')))
2177  {
2178  if (ConvertToI(&Lreorder, frame_pos))
2179  return GENERIC_EXIT_WRITE_FRAME_ERROR;
2180  ptsorder_eq_dtsorder = true;
2181  }
2182  else if (!new_discard_state &&
2183  GetFrameTypeT(curFrame) == 'I')
2184  {
2185  vFrame.move(frame_pos, frame_pos + curIndex);
2186  ptsorder_eq_dtsorder = true;
2187  }
2188 
2189  //convert from presentation-order to decode-order
2190  markedFrame = vFrame.at(frame_pos + curIndex);
2191 
2192  if (!new_discard_state)
2193  {
2194  AddSequence(markedFrame, seqFrame);
2195  RenumberFrames(frame_pos + curIndex,
2196  - GetFrameNum(markedFrame));
2197  }
2198  }
2199 
2200  frame_count++;
2201  }
2202 
2203  if (!Lreorder.isEmpty())
2204  lastRealvPkt = Lreorder.last()->pkt;
2205 
2206  if (markedFrame || !discard)
2207  {
2208  //check for PTS discontinuity
2209  for (FrameList::Iterator it2 = Lreorder.begin();
2210  it2 != Lreorder.end(); it2++)
2211  {
2212  MPEG2frame *curFrame = (*it2);
2213  if (markedFrameP && discard)
2214  {
2215  if (curFrame != markedFrameP)
2216  continue;
2217 
2218  markedFrameP = NULL;
2219  }
2220 
2221  dec2x33(&curFrame->pkt.pts,
2222  poq.Get(vid_id, &curFrame->pkt));
2223  deltaPTS = diff2x33(curFrame->pkt.pts,
2224  expectedvPTS / 300);
2225 
2226  if (deltaPTS < -2 || deltaPTS > 2)
2227  {
2228  LOG(VB_PROCESS, LOG_INFO,
2229  QString("PTS discrepancy: %1 != %2 on "
2230  "%3-Type (%4)")
2231  .arg(curFrame->pkt.pts)
2232  .arg(expectedvPTS / 300)
2233  .arg(GetFrameTypeT(curFrame))
2234  .arg(GetFrameNum(curFrame)));
2235  }
2236 
2237  //remove repeat_first_field if necessary
2238  if (no_repeat)
2239  SetRepeat(curFrame, 2, 0);
2240 
2241  //force PTS to stay in sync (this could be a bad idea!)
2242  if (fix_PTS)
2243  curFrame->pkt.pts = expectedvPTS / 300;
2244 
2245  if (deltaPTS > ptsIncrement*maxframes)
2246  {
2247  LOG(VB_GENERAL, LOG_NOTICE,
2248  QString("Need to insert %1 frames > max "
2249  "allowed: %2. Assuming bad PTS")
2250  .arg((int)(deltaPTS / ptsIncrement))
2251  .arg(maxframes));
2252  curFrame->pkt.pts = expectedvPTS / 300;
2253  deltaPTS = 0;
2254  }
2255 
2256  lastPTS = expectedvPTS;
2257  expectedvPTS += 150 * ptsIncrement *
2258  GetNbFields(curFrame);
2259 
2260  if (curFrame == markedFrameP && new_discard_state)
2261  break;
2262  }
2263 
2264  // dtsExtra is applied at the end of this block if the
2265  // current tail has repeat_first_field set
2266  if (ptsorder_eq_dtsorder)
2267  dtsExtra = 0;
2268  else
2269  dtsExtra = 150 * ptsIncrement *
2270  (GetNbFields(vFrame.at(frame_pos)) - 2);
2271 
2272  if (!markedFrame && deltaPTS > (4 * ptsIncrement / 5))
2273  {
2274  // if we are off by more than 1/2 frame, it is time to
2275  // add a frame
2276  // The frame(s) will be added right after lVpkt_tail,
2277  // and lVpkt_head will be adjusted accordingly
2278 
2279  vFrame.at(frame_pos)->pkt.pts = lastPTS / 300;
2280  int ret = InsertFrame(GetFrameNum(vFrame.at(frame_pos)),
2281  deltaPTS, ptsIncrement, 0);
2282 
2283  if (ret < 0)
2284  return GENERIC_EXIT_WRITE_FRAME_ERROR;
2285 
2286  for (int index = frame_pos + Lreorder.count();
2287  ret && index < vFrame.count(); index++, --ret)
2288  {
2289  lastPTS = expectedvPTS;
2290  expectedvPTS += 150 * ptsIncrement *
2291  GetNbFields(vFrame.at(index));
2292  Lreorder.append(vFrame.at(index));
2293  }
2294  }
2295 
2296  // Set DTS (ignore any current values), and send frame to
2297  // multiplexer
2298 
2299  for (int i = 0; i < Lreorder.count(); i++, frame_pos++)
2300  {
2301  MPEG2frame *curFrame = vFrame.at(frame_pos);
2302  if (discard)
2303  {
2304  if (curFrame != markedFrame)
2305  continue;
2306 
2307  discard = false;
2308  markedFrame = NULL;
2309  }
2310 
2311  curFrame->pkt.dts = (expectedDTS / 300);
2312 #if 0
2313  if (GetFrameTypeT(curFrame) == 'B')
2314  curFrame->pkt.pts = (expectedDTS / 300);
2315 #endif
2316  expectedDTS += 150 * ptsIncrement *
2317  ((!ptsorder_eq_dtsorder && i == 0) ? 2 :
2318  GetNbFields(curFrame));
2319  LOG(VB_FRAME, LOG_INFO,
2320  QString("VID: %1 #:%2 nb: %3 pts: %4 dts: %5 "
2321  "pos: %6")
2322  .arg(GetFrameTypeT(curFrame))
2323  .arg(GetFrameNum(curFrame))
2324  .arg(GetNbFields(curFrame))
2325  .arg(PtsTime(curFrame->pkt.pts))
2326  .arg(PtsTime(curFrame->pkt.dts))
2327  .arg(curFrame->pkt.pos));
2328  if (AddFrame(curFrame))
2329  return GENERIC_EXIT_DEADLOCK;
2330 
2331  if (curFrame == markedFrame)
2332  {
2333  markedFrame = NULL;
2334  discard = true;
2335  }
2336  }
2337 
2338  expectedDTS += dtsExtra;
2339  }
2340  else
2341  {
2342  frame_pos += Lreorder.count();
2343  }
2344  if (PTSdiscrep)
2345  poq.SetNextPos(add2x33(poq.Get(vid_id, &lastRealvPkt),
2346  PTSdiscrep), lastRealvPkt);
2347  }
2348 
2349  if (discard)
2350  cutEndPTS = lastRealvPkt.pts;
2351 
2352  if (file_end)
2353  use_secondary = false;
2354  if (vFrame.count() > 1 || file_end)
2355  StoreSecondary();
2356  }
2357 
2358  for (FrameMap::Iterator it = aFrame.begin(); it != aFrame.end(); it++)
2359  {
2360  FrameList *af = (*it);
2361  AVCodecContext *CC = getCodecContext(it.key());
2362  AVCodecParserContext *CPC = getCodecParserContext(it.key());
2363  bool backwardsPTS = false;
2364 
2365  while (af->count())
2366  {
2367  // What to do if the CC is corrupt?
2368  // Just wait and hope it repairs itself
2369  if (CC->sample_rate == 0 || !CPC || CPC->duration == 0)
2370  break;
2371 
2372  // The order of processing frames is critical to making
2373  // everything work. Backwards PTS discrepancies complicate
2374  // the processing significantly
2375  // Processing works as follows:
2376  // detect whether there is a discontinuous PTS (tmpPTS != 0)
2377  // in the audio stream only.
2378  // next check if a cutpoint is active, and discard frames
2379  // as needed
2380  // next check that the current PTS < last video PTS
2381  // if we get this far, update the expected PTS, and write out
2382  // the audio frame
2383  int64_t nextPTS, tmpPTS;
2384  int64_t incPTS =
2385  90000LL * (int64_t)CPC->duration / CC->sample_rate;
2386 
2387  if (poq.UpdateOrigPTS(it.key(), origaPTS[it.key()],
2388  af->first()->pkt) < 0)
2389  {
2390  backwardsPTS = true;
2391  af_dlta_cnt[it.key()] = 0;
2392  }
2393 
2394  tmpPTS = diff2x33(af->first()->pkt.pts,
2395  origaPTS[it.key()] / 300);
2396 
2397  if (tmpPTS < -incPTS)
2398  {
2399 #ifdef DEBUG_AUDIO
2400  LOG(VB_PROCESS, LOG_INFO,
2401  QString("Aud discard: PTS %1 < %2")
2402  .arg(PtsTime(af->first()->pkt.pts))
2403  .arg(PtsTime(origaPTS[it.key()] / 300)));
2404 #endif
2405  framePool.enqueue(af->takeFirst());
2406  af_dlta_cnt[it.key()] = 0;
2407  continue;
2408  }
2409 
2410  if (tmpPTS > incPTS * maxframes)
2411  {
2412  LOG(VB_PROCESS, LOG_INFO,
2413  QString("Found invalid audio PTS (off by %1) at %2")
2414  .arg(PtsTime(tmpPTS))
2415  .arg(PtsTime(origaPTS[it.key()] / 300)));
2416  if (backwardsPTS && tmpPTS < 90000LL)
2417  {
2418  //there are missing audio frames
2419  LOG(VB_PROCESS, LOG_INFO,
2420  "Fixing missing audio frames");
2421  ptsinc((uint64_t *)&origaPTS[it.key()], 300 * tmpPTS);
2422  backwardsPTS = false;
2423  }
2424  else if (tmpPTS < 90000LL * 4) // 4 seconds
2425  {
2426  if (af_dlta_cnt[it.key()] >= 20)
2427  {
2428  //If there are 20 consecutive frames with an
2429  //offset < 4sec, assume a mismatch and correct.
2430  //Note: if we allow too much discrepancy,
2431  //we could overrun the video queue
2432  ptsinc((uint64_t *)&origaPTS[it.key()],
2433  300 * tmpPTS);
2434  af_dlta_cnt[it.key()] = 0;
2435  }
2436  else
2437  af_dlta_cnt[it.key()]++;
2438  }
2439  af->first()->pkt.pts = origaPTS[it.key()] / 300;
2440  }
2441  else if (tmpPTS > incPTS) //correct for small discrepancies
2442  {
2443  incPTS += incPTS;
2444  backwardsPTS = false;
2445  af_dlta_cnt[it.key()] = 0;
2446  }
2447  else
2448  {
2449  backwardsPTS = false;
2450  af_dlta_cnt[it.key()] = 0;
2451  }
2452 
2453  nextPTS = add2x33(af->first()->pkt.pts,
2454  90000LL * (int64_t)CPC->duration / CC->sample_rate);
2455 
2456  if ((cutState[it.key()] == 1 &&
2457  cmp2x33(nextPTS, cutStartPTS) > 0) ||
2458  (cutState[it.key()] == 2 &&
2459  cmp2x33(af->first()->pkt.pts, cutEndPTS) < 0))
2460  {
2461 #ifdef DEBUG_AUDIO
2462  LOG(VB_PROCESS, LOG_INFO,
2463  QString("Aud in cutpoint: %1 > %2 && %3 < %4")
2464  .arg(PtsTime(nextPTS)).arg(PtsTime(cutStartPTS))
2465  .arg(PtsTime(af->first()->pkt.pts))
2466  .arg(PtsTime(cutEndPTS)));
2467 #endif
2468  framePool.enqueue(af->takeFirst());
2469  cutState[it.key()] = 2;
2470  ptsinc((uint64_t *)&origaPTS[it.key()], incPTS * 300);
2471  continue;
2472  }
2473 
2474  int64_t deltaPTS = poq.Get(it.key(), &af->first()->pkt);
2475 
2476  if (udiff2x33(nextPTS, deltaPTS) * 300 > expectedDTS &&
2477  cutState[it.key()] != 1)
2478  {
2479 #ifdef DEBUG_AUDIO
2480  LOG(VB_PROCESS, LOG_INFO, QString("Aud not ready: %1 > %2")
2481  .arg(PtsTime(udiff2x33(nextPTS, deltaPTS)))
2482  .arg(PtsTime(expectedDTS / 300)));
2483 #endif
2484  break;
2485  }
2486 
2487  if (cutState[it.key()] == 2)
2488  cutState[it.key()] = 0;
2489 
2490  ptsinc((uint64_t *)&origaPTS[it.key()], incPTS * 300);
2491 
2492  dec2x33(&af->first()->pkt.pts, deltaPTS);
2493 
2494 #if 0
2495  expectedPTS[it.key()] = udiff2x33(nextPTS, initPTS);
2496  write_audio(lApkt_tail->pkt, initPTS);
2497 #endif
2498  LOG(VB_FRAME, LOG_INFO, QString("AUD #%1: pts: %2 pos: %3")
2499  .arg(it.key())
2500  .arg(PtsTime(af->first()->pkt.pts))
2501  .arg(af->first()->pkt.pos));
2502  if (AddFrame(af->first()))
2503  return GENERIC_EXIT_DEADLOCK;
2504  framePool.enqueue(af->takeFirst());
2505  }
2506  }
2507  }
2508 
2509  rx.done = 1;
2510  pthread_mutex_lock( &rx.mutex );
2511  pthread_cond_signal(&rx.cond);
2512  pthread_mutex_unlock( &rx.mutex );
2513  pthread_join(thread, NULL);
2514 
2515  avformat_close_input(&inputFC);
2516  inputFC = NULL;
2517  return REENCODE_OK;
2518 }
2519 
2520 #ifdef NO_MYTH
2521 int verboseMask = VB_GENERAL;
2522 
2523 void usage(char *s)
2524 {
2525  fprintf(stderr, "%s usage:\n", s);
2526  fprintf(stderr, "\t--infile <file> -i <file> : Input mpg file\n");
2527  fprintf(stderr, "\t--outfile <file> -o <file> : Output mpg file\n");
2528  fprintf(stderr, "\t--dbg_lvl # -d # : Debug level\n");
2529  fprintf(stderr, "\t--maxframes # -m # : Max frames to insert at once (default=10)\n");
2530  fprintf(stderr, "\t--cutlist \"start - end\" -c : Apply a cutlist. Specify on e'-c' per cut\n");
2531  fprintf(stderr, "\t--no3to2 -t : Remove 3:2 pullup\n");
2532  fprintf(stderr, "\t--fixup -f : make PTS continuous\n");
2533  fprintf(stderr, "\t--ostream <dvd|ps> -e : Output stream type (defaults to ps)\n");
2534  fprintf(stderr, "\t--showprogress -p : show progress\n");
2535  fprintf(stderr, "\t--help -h : This screen\n");
2536  exit(0);
2537 }
2538 
2539 int main(int argc, char **argv)
2540 {
2541  QStringList cutlist;
2542  QStringList savelist;
2543  char *infile = NULL, *outfile = NULL, *format = NULL;
2544  int no_repeat = 0, fix_PTS = 0, max_frames = 20, otype = REPLEX_MPEG2;
2545  bool showprogress = 0;
2546  const struct option long_options[] =
2547  {
2548  {"infile", required_argument, NULL, 'i'},
2549 
2550  {"outfile", required_argument, NULL, 'o'},
2551  {"format", required_argument, NULL, 'r'},
2552  {"dbg_lvl", required_argument, NULL, 'd'},
2553  {"cutlist", required_argument, NULL, 'c'},
2554  {"saveframe", required_argument, NULL, 's'},
2555  {"ostream", required_argument, NULL, 'e'},
2556  {"no3to2", no_argument, NULL, 't'},
2557  {"fixup", no_argument, NULL, 'f'},
2558  {"showprogress", no_argument, NULL, 'p'},
2559  {"help", no_argument , NULL, 'h'},
2560  {0, 0, 0, 0}
2561  };
2562 
2563  while (1)
2564  {
2565  int option_index = 0;
2566  char c;
2567  c = getopt_long (argc, argv, "i:o:d:r:m:c:s:e:tfph",
2568  long_options, &option_index);
2569 
2570  if (c == -1)
2571  break;
2572 
2573  switch (c)
2574  {
2575 
2576  case 'i':
2577  infile = optarg;
2578  break;
2579 
2580  case 'o':
2581  outfile = optarg;
2582  break;
2583 
2584  case 'r':
2585  format = optarg;
2586  break;
2587 
2588  case 'e':
2589  if (strlen(optarg) == 3 && strncmp(optarg, "dvd", 3) == 0)
2590  otype = REPLEX_DVD;
2591  break;
2592 
2593  case 'd':
2594  verboseMask = atoi(optarg);
2595  break;
2596 
2597  case 'm':
2598  max_frames = atoi(optarg);
2599  break;
2600 
2601  case 'c':
2602  cutlist.append(optarg);
2603  break;
2604 
2605  case 't':
2606  no_repeat = 1;
2607 
2608  case 'f':
2609  fix_PTS = 1;
2610  break;
2611 
2612  case 's':
2613  savelist.append(optarg);
2614  break;
2615 
2616  case 'p':
2617  showprogress = true;
2618  break;
2619 
2620  case 'h':
2621 
2622  case '?':
2623 
2624  default:
2625  usage(argv[0]);
2626  }
2627  }
2628 
2629  if (infile == NULL || outfile == NULL)
2630  usage(argv[0]);
2631 
2632  MPEG2fixup m2f(infile, outfile, NULL, format,
2633  no_repeat, fix_PTS, max_frames,
2634  showprogress, otype);
2635 
2636  if (cutlist.count())
2637  m2f.AddRangeList(cutlist, MPF_TYPE_CUTLIST);
2638  if (savelist.count())
2639  m2f.AddRangeList(savelist, MPF_TYPE_SAVELIST);
2640  return m2f.Start();
2641 }
2642 #endif
2643 
2645  frm_pos_map_t &posMap,
2646  frm_pos_map_t &durMap)
2647 {
2648  LOG(VB_GENERAL, LOG_INFO, "Generating Keyframe Index");
2649 
2650  AVPacket pkt;
2651  int count = 0;
2652 
2653  /*============ initialise AV ===============*/
2654  if (!InitAV(file, NULL, 0))
2655  return GENERIC_EXIT_NOT_OK;
2656 
2657  if (mkvfile)
2658  {
2659  LOG(VB_GENERAL, LOG_INFO, "Seek tables are not required for MKV");
2660  return GENERIC_EXIT_NOT_OK;
2661  }
2662 
2663  av_init_packet(&pkt);
2664 
2665  uint64_t totalDuration = 0;
2666  while (av_read_frame(inputFC, &pkt) >= 0)
2667  {
2668  if (pkt.stream_index == vid_id)
2669  {
2670  if (pkt.flags & AV_PKT_FLAG_KEY)
2671  {
2672  posMap[count] = pkt.pos;
2673  durMap[count] = totalDuration;
2674  }
2675 
2676  // XXX totalDuration untested. Results should be the same
2677  // as from mythcommflag --rebuild.
2678 
2679  // totalDuration calculation based on
2680  // AvFormatDecoder::PreProcessVideoPacket()
2681  totalDuration +=
2682  av_q2d(inputFC->streams[pkt.stream_index]->time_base) *
2683  pkt.duration * 1000; // msec
2684  count++;
2685  }
2686  av_free_packet(&pkt);
2687  }
2688 
2689  // Close input file
2690  avformat_close_input(&inputFC);
2691  inputFC = NULL;
2692 
2693  LOG(VB_GENERAL, LOG_NOTICE, "Transcode Completed");
2694 
2695  return REENCODE_OK;
2696 }
2697 
2698 /*
2699  * vim:ts=4:sw=4:ai:et:si:sts=4
2700  */