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