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