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