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