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  ssize_t ret = write(fh, info->display_fbuf->buf[0],
1105  static_cast<size_t>(info->sequence->width) *
1106  static_cast<size_t>(info->sequence->height));
1107  if (ret < 0)
1108  {
1109  LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
1110  ENO);
1111  goto closefd;
1112  }
1113  ret = write(fh, info->display_fbuf->buf[1],
1114  static_cast<size_t>(info->sequence->chroma_width) *
1115  static_cast<size_t>(info->sequence->chroma_height));
1116  if (ret < 0)
1117  {
1118  LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
1119  ENO);
1120  goto closefd;
1121  }
1122  ret = write(fh, info->display_fbuf->buf[2],
1123  static_cast<size_t>(info->sequence->chroma_width) *
1124  static_cast<size_t>(info->sequence->chroma_height));
1125  if (ret < 0)
1126  {
1127  LOG(VB_GENERAL, LOG_ERR, QString("write failed %1: ").arg(filename) +
1128  ENO);
1129  goto closefd;
1130  }
1131 closefd:
1132  close(fh);
1133 }
1134 
1135 void MPEG2fixup::WriteData(const QString& filename, uint8_t *data, int size)
1136 {
1137  int fh = open(filename.toLocal8Bit().constData(),
1138  O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
1139  if (fh == -1)
1140  {
1141  LOG(VB_GENERAL, LOG_ERR,
1142  QString("Couldn't open file %1: ").arg(filename) + ENO);
1143  return;
1144  }
1145 
1146  int ret = write(fh, data, size);
1147  if (ret < 0)
1148  LOG(VB_GENERAL, LOG_ERR, QString("write failed %1").arg(filename) +
1149  ENO);
1150  close(fh);
1151 }
1152 
1153 bool MPEG2fixup::BuildFrame(AVPacket *pkt, const QString& fname)
1154 {
1155  alignas(16) std::array<uint16_t,64> intra_matrix {};
1156  int64_t savedPts = pkt->pts; // save the original pts
1157 
1158  const mpeg2_info_t *info = mpeg2_info(m_imgDecoder);
1159  if (!info->display_fbuf)
1160  return true;
1161 
1162  int outbuf_size = info->sequence->width * info->sequence->height * 2;
1163 
1164  if (!fname.isEmpty())
1165  {
1166  QString tmpstr = fname + ".yuv";
1167  WriteYUV(tmpstr, info);
1168  }
1169 
1170  if (!m_picture)
1171  {
1172  if (!(m_picture = av_frame_alloc()))
1173  {
1174  return true;
1175  }
1176  }
1177  else
1178  {
1179  av_frame_unref(m_picture);
1180  }
1181 
1182  //pkt->data = (uint8_t *)av_malloc(outbuf_size);
1183  if (pkt->size < outbuf_size)
1184  av_grow_packet(pkt, (outbuf_size - pkt->size));
1185 
1186  m_picture->data[0] = info->display_fbuf->buf[0];
1187  m_picture->data[1] = info->display_fbuf->buf[1];
1188  m_picture->data[2] = info->display_fbuf->buf[2];
1189 
1190  m_picture->linesize[0] = info->sequence->width;
1191  m_picture->linesize[1] = info->sequence->chroma_width;
1192  m_picture->linesize[2] = info->sequence->chroma_width;
1193 
1194  m_picture->opaque = info->display_fbuf->id;
1195 
1196 #if 0 //RUN_ONCE
1197  static constexpr std::array<uint8_t, 64> k_zigzag_scan = {
1198  0, 1, 8, 16, 9, 2, 3, 10,
1199  17, 24, 32, 25, 18, 11, 4, 5,
1200  12, 19, 26, 33, 40, 48, 41, 34,
1201  27, 20, 13, 6, 7, 14, 21, 28,
1202  35, 42, 49, 56, 57, 50, 43, 36,
1203  29, 22, 15, 23, 30, 37, 44, 51,
1204  58, 59, 52, 45, 38, 31, 39, 46,
1205  53, 60, 61, 54, 47, 55, 62, 63
1206  };
1207 
1208  static std::array<uint16_t, 64> k_invZigzagDirect16 = {};
1209  for (int i = 0; i < 64; i++)
1210  {
1211  k_invZigzagDirect16[k_zigzag_scan[i]] = i;
1212  }
1213 #endif
1214  static constexpr std::array<uint16_t, 64> k_invZigzagDirect16 = {
1215  0, 1, 5, 6, 14, 15, 27, 28,
1216  2, 4, 7, 13, 16, 26, 29, 42,
1217  3, 8, 12, 17, 25, 30, 41, 43,
1218  9, 11, 18, 24, 31, 40, 44, 53,
1219  10, 19, 23, 32, 39, 45, 52, 54,
1220  20, 22, 33, 38, 46, 51, 55, 60,
1221  21, 34, 37, 47, 50, 56, 59, 61,
1222  35, 36, 48, 49, 57, 58, 62, 63,
1223  };
1224 
1225  //copy_quant_matrix(m_imgDecoder, intra_matrix);
1226  for (int i = 0; i < 64; i++)
1227  {
1228  intra_matrix[k_invZigzagDirect16[i]] = m_imgDecoder->quantizer_matrix[0][i];
1229  }
1230 
1231  if (info->display_picture->nb_fields % 2)
1232  {
1233  m_picture->top_field_first = ((info->display_picture->flags &
1234  PIC_FLAG_TOP_FIELD_FIRST) != 0) ? 0 : 1;
1235  }
1236  else
1237  {
1238  m_picture->top_field_first = ((info->display_picture->flags &
1239  PIC_FLAG_TOP_FIELD_FIRST) != 0) ? 1 : 0;
1240  }
1241 
1242  m_picture->interlaced_frame = ((info->display_picture->flags &
1243  PIC_FLAG_PROGRESSIVE_FRAME) != 0) ? 0 : 1;
1244 
1245  const AVCodec *out_codec = avcodec_find_encoder(AV_CODEC_ID_MPEG2VIDEO);
1246  if (!out_codec)
1247  {
1248  LOG(VB_GENERAL, LOG_ERR, "Couldn't find MPEG2 encoder");
1249  return true;
1250  }
1251 
1252  AVCodecContext *c = avcodec_alloc_context3(nullptr);
1253 
1254  //NOTE: The following may seem wrong, but avcodec requires
1255  //sequence->progressive == frame->progressive
1256  //We fix the discrepancy by discarding avcodec's sequence header, and
1257  //replace it with the original
1258  if (m_picture->interlaced_frame)
1259  c->flags |= AV_CODEC_FLAG_INTERLACED_DCT;
1260 
1261  c->bit_rate = info->sequence->byte_rate << 3; //not used
1262  c->bit_rate_tolerance = c->bit_rate >> 2; //not used
1263  c->width = info->sequence->width;
1264  c->height = info->sequence->height;
1265  av_reduce(&c->time_base.num, &c->time_base.den,
1266  info->sequence->frame_period, 27000000LL, 100000);
1267  c->pix_fmt = AV_PIX_FMT_YUV420P;
1268  c->max_b_frames = 0;
1269  c->has_b_frames = 0;
1270  // c->rc_buffer_aggressivity = 1;
1271  // rc_buf_aggressivity is now "currently useless"
1272 
1273  // c->profile = vidCC->profile;
1274  // c->level = vidCC->level;
1275  c->rc_buffer_size = 0;
1276  c->gop_size = 0; // this should force all i-frames
1277  // c->flags=CODEC_FLAG_LOW_DELAY;
1278 
1279  if (intra_matrix[0] == 0x08)
1280  c->intra_matrix = intra_matrix.data();
1281 
1282  c->qmin = c->qmax = 2;
1283 
1284  m_picture->width = info->sequence->width;
1285  m_picture->height = info->sequence->height;
1286  m_picture->format = AV_PIX_FMT_YUV420P;
1287  m_picture->pts = AV_NOPTS_VALUE;
1288  m_picture->key_frame = 1;
1289  m_picture->pict_type = AV_PICTURE_TYPE_NONE;
1290  m_picture->quality = 0;
1291 
1292  if (avcodec_open2(c, out_codec, nullptr) < 0)
1293  {
1294  LOG(VB_GENERAL, LOG_ERR, "could not open codec");
1295  return true;
1296  }
1297 
1298  int got_packet = 0;
1299  int ret = avcodec_send_frame(c, m_picture);
1300 
1301  bool flushed = false;
1302  while (ret >= 0)
1303  {
1304  // ret = avcodec_encode_video2(c, pkt, m_picture, &got_packet);
1305  ret = avcodec_receive_packet(c, pkt);
1306  if (ret == 0)
1307  got_packet = 1;
1308  if (ret == AVERROR(EAGAIN))
1309  ret = 0;
1310  if (ret < 0)
1311  break;
1312  if (flushed)
1313  break;
1314  // flush
1315  ret = avcodec_send_frame(c, nullptr);
1316  flushed = true;
1317  }
1318 
1319  if (ret < 0 || !got_packet)
1320  {
1321  LOG(VB_GENERAL, LOG_ERR,
1322  QString("avcodec_encode_video2 failed (%1)").arg(ret));
1323  return true;
1324  }
1325 
1326  if (!fname.isEmpty())
1327  {
1328  QString ename = fname + ".enc";
1329  WriteData(ename, pkt->data, pkt->size);
1330 
1331  QString yname = fname + ".enc.yuv";
1332  WriteFrame(yname, pkt);
1333  }
1334  int delta = FindMPEG2Header(pkt->data, pkt->size, 0x00);
1335  // out_size=avcodec_encode_video(c, outbuf, outbuf_size, m_picture);
1336  // HACK: a hack to get to the picture frame
1337  //pkt->size -= delta; // a hack to get to the picture frame
1338  int newSize = pkt->size - delta;
1339  pkt->pts = savedPts; // restore the original pts
1340  memmove(pkt->data, pkt->data + delta, newSize);
1341  av_shrink_packet(pkt, newSize); // Shrink packet to it's new size
1342  // End HACK
1343 
1344  SetRepeat(pkt->data, pkt->size, info->display_picture->nb_fields,
1345  ((info->display_picture->flags & PIC_FLAG_TOP_FIELD_FIRST) != 0U));
1346 
1347  avcodec_free_context(&c);
1348 
1349  return false;
1350 }
1351 
1352 static constexpr int MAX_FRAMES { 20000 };
1354 {
1355  MPEG2frame *f = nullptr;
1356 
1357  if (m_framePool.isEmpty())
1358  {
1359  static int s_frameCount = 0;
1360  if (s_frameCount >= MAX_FRAMES)
1361  {
1362  LOG(VB_GENERAL, LOG_ERR, "No more queue slots!");
1363  return nullptr;
1364  }
1365  f = new MPEG2frame(pkt->size);
1366  s_frameCount++;
1367  }
1368  else
1369  f = m_framePool.dequeue();
1370 
1371  f->set_pkt(pkt);
1372 
1373  return f;
1374 }
1375 
1377 {
1378  MPEG2frame *tmpFrame = GetPoolFrame(f->m_pkt);
1379  if (!tmpFrame)
1380  return tmpFrame;
1381 
1382  tmpFrame->m_isSequence = f->m_isSequence;
1383  tmpFrame->m_isGop = f->m_isGop;
1384  tmpFrame->m_mpeg2_seq = f->m_mpeg2_seq;
1385  tmpFrame->m_mpeg2_gop = f->m_mpeg2_gop;
1386  tmpFrame->m_mpeg2_pic = f->m_mpeg2_pic;
1387  return tmpFrame;
1388 }
1389 
1390 int MPEG2fixup::GetFrame(AVPacket *pkt)
1391 {
1392  while (true)
1393  {
1394  bool done = false;
1395  if (!m_unreadFrames.isEmpty())
1396  {
1397  m_vFrame.append(m_unreadFrames.dequeue());
1398  if (m_realFileEnd && m_unreadFrames.isEmpty())
1399  m_fileEnd = true;
1400  return static_cast<int>(m_fileEnd);
1401  }
1402 
1403  while (!done)
1404  {
1405  pkt->pts = AV_NOPTS_VALUE;
1406  pkt->dts = AV_NOPTS_VALUE;
1407  int ret = av_read_frame(m_inputFC, pkt);
1408 
1409  if (ret < 0)
1410  {
1411  // If it is EAGAIN, obey it, dangit!
1412  if (ret == -EAGAIN)
1413  continue;
1414 
1415  //insert a bogus frame (this won't be written out)
1416  if (m_vFrame.isEmpty())
1417  {
1418  LOG(VB_GENERAL, LOG_ERR,
1419  "Found end of file without finding any frames");
1420  av_packet_unref(pkt);
1421  return 1;
1422  }
1423 
1424  MPEG2frame *tmpFrame = GetPoolFrame(m_vFrame.last()->m_pkt);
1425  if (tmpFrame == nullptr)
1426  {
1427  av_packet_unref(pkt);
1428  return 1;
1429  }
1430 
1431  m_vFrame.append(tmpFrame);
1432  m_realFileEnd = true;
1433  m_fileEnd = true;
1434  return 1;
1435  }
1436 
1437  if (pkt->stream_index == m_vidId ||
1438  m_aFrame.contains(pkt->stream_index))
1439  done = true;
1440  else
1441  av_packet_unref(pkt);
1442  }
1443  pkt->duration = m_frameNum++;
1444  if ((m_showProgress || m_updateStatus) &&
1446  {
1447  float percent_done = 100.0 * pkt->pos / m_fileSize;
1448  if (m_updateStatus)
1449  m_updateStatus(percent_done);
1450  if (m_showProgress)
1451  LOG(VB_GENERAL, LOG_INFO, QString("%1% complete")
1452  .arg(percent_done, 0, 'f', 1));
1453  if (m_checkAbort && m_checkAbort())
1454  return REENCODE_STOPPED;
1457  }
1458 
1459 #ifdef DEBUG_AUDIO
1460  LOG(VB_DECODE, LOG_INFO, QString("Stream: %1 PTS: %2 DTS: %3 pos: %4")
1461  .arg(pkt->stream_index)
1462  .arg((pkt->pts == AV_NOPTS_VALUE) ? "NONE" : PtsTime(pkt->pts))
1463  .arg((pkt->dts == AV_NOPTS_VALUE) ? "NONE" : PtsTime(pkt->dts))
1464  .arg(pkt->pos));
1465 #endif
1466 
1467  MPEG2frame *tmpFrame = GetPoolFrame(pkt);
1468  if (tmpFrame == nullptr)
1469  {
1470  av_packet_unref(pkt);
1471  return 1;
1472  }
1473 
1474  switch (m_inputFC->streams[pkt->stream_index]->codecpar->codec_type)
1475  {
1476  case AVMEDIA_TYPE_VIDEO:
1477  m_vFrame.append(tmpFrame);
1478  av_packet_unref(pkt);
1479 
1480  if (!ProcessVideo(m_vFrame.last(), m_headerDecoder))
1481  return 0;
1482  m_framePool.enqueue(m_vFrame.takeLast());
1483  break;
1484 
1485  case AVMEDIA_TYPE_AUDIO:
1486  if (m_aFrame.contains(pkt->stream_index))
1487  {
1488  m_aFrame[pkt->stream_index]->append(tmpFrame);
1489  }
1490  else
1491  {
1492  LOG(VB_GENERAL, LOG_DEBUG,
1493  QString("Invalid stream ID %1, ignoring").arg(pkt->stream_index));
1494  m_framePool.enqueue(tmpFrame);
1495  }
1496  av_packet_unref(pkt);
1497  return 0;
1498 
1499  default:
1500  m_framePool.enqueue(tmpFrame);
1501  av_packet_unref(pkt);
1502  return 1;
1503  }
1504  }
1505 }
1506 
1508 {
1509  QMap <int, bool> found;
1510  AVPacket *pkt = av_packet_alloc();
1511  if (pkt == nullptr)
1512  {
1513  LOG(VB_PROCESS, LOG_ERR, "packet allocation failed");
1514  return false;
1515  }
1516 
1517  do
1518  {
1519  if (GetFrame(pkt))
1520  {
1521  av_packet_free(&pkt);
1522  return false;
1523  }
1524 
1525  if (m_vidId == pkt->stream_index)
1526  {
1527  while (!m_vFrame.isEmpty())
1528  {
1529  if (m_vFrame.first()->m_isSequence)
1530  {
1531  if (pkt->pos != m_vFrame.first()->m_pkt->pos)
1532  break;
1533 
1534  if (pkt->pts != AV_NOPTS_VALUE ||
1535  pkt->dts != AV_NOPTS_VALUE)
1536  {
1537  if (pkt->pts == AV_NOPTS_VALUE)
1538  m_vFrame.first()->m_pkt->pts = pkt->dts;
1539 
1540  LOG(VB_PROCESS, LOG_INFO,
1541  "Found 1st valid video frame");
1542  break;
1543  }
1544  }
1545 
1546  LOG(VB_PROCESS, LOG_INFO, "Dropping V packet");
1547 
1548  m_framePool.enqueue(m_vFrame.takeFirst());
1549  }
1550  }
1551 
1552  if (m_vFrame.isEmpty())
1553  continue;
1554 
1555  for (auto it = m_aFrame.begin(); it != m_aFrame.end(); it++)
1556  {
1557  if (found.contains(it.key()))
1558  continue;
1559 
1560  FrameList *af = (*it);
1561 
1562  while (!af->isEmpty())
1563  {
1564  int64_t delta = diff2x33(af->first()->m_pkt->pts,
1565  m_vFrame.first()->m_pkt->pts);
1566  if (delta < -180000 || delta > 180000) //2 seconds
1567  {
1568  //Check all video sequence packets against current
1569  //audio packet
1570  MPEG2frame *foundframe = nullptr;
1571  for (auto *currFrame : qAsConst(m_vFrame))
1572  {
1573  if (currFrame->m_isSequence)
1574  {
1575  int64_t dlta1 = diff2x33(af->first()->m_pkt->pts,
1576  currFrame->m_pkt->pts);
1577  if (dlta1 >= -180000 && dlta1 <= 180000)
1578  {
1579  foundframe = currFrame;
1580  delta = dlta1;
1581  break;
1582  }
1583  }
1584  }
1585 
1586  while (foundframe && m_vFrame.first() != foundframe)
1587  {
1588  m_framePool.enqueue(m_vFrame.takeFirst());
1589  }
1590  }
1591 
1592  if (delta < -180000 || delta > 180000) //2 seconds
1593  {
1594  LOG(VB_PROCESS, LOG_INFO,
1595  QString("Dropping A packet from stream %1")
1596  .arg(it.key()));
1597  LOG(VB_PROCESS, LOG_INFO, QString(" A:%1 V:%2")
1598  .arg(PtsTime(af->first()->m_pkt->pts),
1599  PtsTime(m_vFrame.first()->m_pkt->pts)));
1600  m_framePool.enqueue(af->takeFirst());
1601  continue;
1602  }
1603 
1604  if (delta < 0 && af->count() > 1)
1605  {
1606  if (cmp2x33(af->at(1)->m_pkt->pts,
1607  m_vFrame.first()->m_pkt->pts) > 0)
1608  {
1609  LOG(VB_PROCESS, LOG_INFO,
1610  QString("Found useful audio frame from stream %1")
1611  .arg(it.key()));
1612  found[it.key()] = true;
1613  break;
1614  }
1615  LOG(VB_PROCESS, LOG_INFO,
1616  QString("Dropping A packet from stream %1")
1617  .arg(it.key()));
1618  m_framePool.enqueue(af->takeFirst());
1619  continue;
1620  }
1621  if (delta >= 0)
1622  {
1623  LOG(VB_PROCESS, LOG_INFO,
1624  QString("Found useful audio frame from stream %1")
1625  .arg(it.key()));
1626  found[it.key()] = true;
1627  break;
1628  }
1629 
1630  if (af->count() == 1)
1631  break;
1632  }
1633  }
1634  } while (found.count() != m_aFrame.count());
1635 
1636  av_packet_free(&pkt);
1637  return true;
1638 }
1639 
1640 void MPEG2fixup::SetRepeat(MPEG2frame *vf, int fields, bool topff)
1641 {
1642  vf->m_mpeg2_pic.nb_fields = 2;
1643  SetRepeat(vf->m_framePos, vf->m_pkt->data + vf->m_pkt->size - vf->m_framePos,
1644  fields, topff);
1645 }
1646 
1647 void MPEG2fixup::SetRepeat(uint8_t *ptr, int size, int fields, bool topff)
1648 {
1649  uint8_t *end = ptr + size;
1650  uint8_t setmask = 0x00;
1651  uint8_t clrmask = 0xff;
1652  if (topff)
1653  setmask |= 0x80;
1654  else
1655  clrmask &= 0x7f;
1656 
1657  if (fields == 2)
1658  clrmask &= 0xfd;
1659  else
1660  setmask |= 0x02;
1661 
1662  while (ptr < end)
1663  {
1664  if (MATCH_HEADER(ptr) && ptr[3] == 0xB5 && (ptr[4] & 0xF0) == 0x80)
1665  {
1666  //unset repeat_first_field
1667  //set top_field_first
1668  ptr[7] |= setmask;
1669  ptr[7] &= clrmask;
1670  return;
1671  }
1672 
1673  ptr++;
1674  }
1675 }
1676 
1678 {
1679  for (const auto & vf : qAsConst(m_vFrame))
1680  {
1681  if (GetFrameNum(vf) == frameNum)
1682  return vf;
1683  }
1684 
1685  return nullptr;
1686 }
1687 
1688 void MPEG2fixup::RenumberFrames(int start_pos, int delta)
1689 {
1690  int maxPos = m_vFrame.count() - 1;
1691 
1692  for (int pos = start_pos; pos < maxPos; pos++)
1693  {
1694  MPEG2frame *frame = m_vFrame.at(pos);
1695  SetFrameNum(frame->m_framePos, GetFrameNum(frame) + delta);
1696  frame->m_mpeg2_pic.temporal_reference += delta;
1697  }
1698 }
1699 
1701 {
1702  while (!m_vSecondary.isEmpty())
1703  {
1704  m_framePool.enqueue(m_vSecondary.takeFirst());
1705  }
1706 
1707  while (m_vFrame.count() > 1)
1708  {
1709  if (m_useSecondary && GetFrameTypeT(m_vFrame.first()) != 'B')
1710  m_vSecondary.append(m_vFrame.takeFirst());
1711  else
1712  m_framePool.enqueue(m_vFrame.takeFirst());
1713  }
1714 }
1715 
1717 {
1718  int frame_num = 0;
1719  mpeg2_reset(m_imgDecoder, 1);
1720  for (const auto & vs : qAsConst(m_vSecondary))
1721  {
1722  SetFrameNum(vs->m_framePos, frame_num++);
1723  if (ProcessVideo(vs, m_imgDecoder) < 0)
1724  return 1;
1725  }
1726  return 0;
1727 }
1728 
1729 MPEG2frame *MPEG2fixup::DecodeToFrame(int frameNum, int skip_reset)
1730 {
1731  MPEG2frame *spare = nullptr;
1732  int found = 0;
1733  bool skip_first = false;
1734  const mpeg2_info_t * info = mpeg2_info(m_imgDecoder);
1735  int maxPos = m_vFrame.count() - 1;
1736 
1737  if (m_vFrame.at(m_displayFrame)->m_isSequence)
1738  {
1739  skip_first = true;
1740  if (!skip_reset && (m_displayFrame != maxPos || m_displayFrame == 0))
1741  mpeg2_reset(m_imgDecoder, 1);
1742  }
1743 
1744  spare = FindFrameNum(frameNum);
1745  if (!spare)
1746  return nullptr;
1747 
1748  int framePos = m_vFrame.indexOf(spare);
1749 
1750  for (int curPos = m_displayFrame; m_displayFrame != maxPos;
1751  curPos++, m_displayFrame++)
1752  {
1754  return nullptr;
1755 
1756  if (!skip_first && curPos >= framePos && info->display_picture &&
1757  (int)info->display_picture->temporal_reference >= frameNum)
1758  {
1759  found = 1;
1760  m_displayFrame++;
1761  break;
1762  }
1763 
1764  skip_first = false;
1765  }
1766 
1767  if (!found)
1768  {
1769  int tmpFrameNum = frameNum;
1770  MPEG2frame *tmpFrame = GetPoolFrame(spare->m_pkt);
1771  if (tmpFrame == nullptr)
1772  return nullptr;
1773 
1774  tmpFrame->m_framePos = tmpFrame->m_pkt->data +
1775  (spare->m_framePos - spare->m_pkt->data);
1776 
1777  while (!info->display_picture ||
1778  (int)info->display_picture->temporal_reference < frameNum)
1779  {
1780  SetFrameNum(tmpFrame->m_framePos, ++tmpFrameNum);
1781  if (ProcessVideo(tmpFrame, m_imgDecoder) < 0)
1782  {
1783  delete tmpFrame;
1784  return nullptr;
1785  }
1786  }
1787 
1788  m_framePool.enqueue(tmpFrame);
1789  }
1790 
1791  if ((int)info->display_picture->temporal_reference > frameNum)
1792  {
1793  // the frame in question doesn't exist. We have no idea where we are.
1794  // reset the displayFrame so we start searching from the beginning next
1795  // time
1796  m_displayFrame = 0;
1797  LOG(VB_GENERAL, LOG_NOTICE,
1798  QString("Frame %1 > %2. Corruption likely at pos: %3")
1799  .arg(info->display_picture->temporal_reference)
1800  .arg(frameNum).arg(spare->m_pkt->pos));
1801  }
1802 
1803  return spare;
1804 }
1805 
1806 int MPEG2fixup::ConvertToI(FrameList *orderedFrames, int headPos)
1807 {
1808  MPEG2frame *spare = nullptr;
1809  AVPacket *pkt = av_packet_alloc();
1810  if (pkt == nullptr)
1811  {
1812  LOG(VB_PROCESS, LOG_ERR, "packet allocation failed");
1813  return 0;
1814  }
1815 #ifdef SPEW_FILES
1816  static int ins_count = 0;
1817 #endif
1818 
1819  //head_pos == 0 means that we are decoding B frames after a seq_header
1820  if (headPos == 0)
1821  {
1822  if (PlaybackSecondary())
1823  {
1824  av_packet_free(&pkt);
1825  return 1;
1826  }
1827  }
1828 
1829  for (const auto & of : qAsConst(*orderedFrames))
1830  {
1831  int i = GetFrameNum(of);
1832  if ((spare = DecodeToFrame(i, static_cast<int>(headPos == 0))) == nullptr)
1833  {
1834  LOG(VB_GENERAL, LOG_WARNING,
1835  QString("ConvertToI skipping undecoded frame #%1").arg(i));
1836  continue;
1837  }
1838 
1839  if (GetFrameTypeT(spare) == 'I')
1840  continue;
1841 
1842  //pkt = spare->m_pkt;
1843  av_packet_ref(pkt, spare->m_pkt);
1844  //pkt->data is a newly malloced area
1845 
1846  QString fname;
1847 
1848 #ifdef SPEW_FILES
1849  if (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY))
1850  fname = QString("cnv%1").arg(ins_count++);
1851 #endif
1852 
1853  if (BuildFrame(pkt, fname))
1854  {
1855  av_packet_free(&pkt);
1856  return 1;
1857  }
1858 
1859  LOG(VB_GENERAL, LOG_INFO,
1860  QString("Converting frame #%1 from %2 to I %3")
1861  .arg(i).arg(GetFrameTypeT(spare)).arg(fname));
1862 
1863  spare->set_pkt(pkt);
1864  av_packet_unref(pkt);
1865  SetFrameNum(spare->m_pkt->data, GetFrameNum(spare));
1866  ProcessVideo(spare, m_headerDecoder); //process this new frame
1867  }
1868 
1869  //reorder frames
1870  m_vFrame.move(headPos, headPos + orderedFrames->count() - 1);
1871  av_packet_free(&pkt);
1872  return 0;
1873 }
1874 
1875 int MPEG2fixup::InsertFrame(int frameNum, int64_t deltaPTS,
1876  int64_t ptsIncrement, int64_t initPTS)
1877 {
1878  MPEG2frame *spare = nullptr;
1879  int increment = 0;
1880  int index = 0;
1881 
1882  AVPacket *pkt = av_packet_alloc();
1883  if (pkt == nullptr)
1884  {
1885  LOG(VB_PROCESS, LOG_ERR, "packet allocation failed");
1886  return 0;
1887  }
1888 
1889  if ((spare = DecodeToFrame(frameNum, 0)) == nullptr)
1890  {
1891  av_packet_free(&pkt);
1892  return -1;
1893  }
1894 
1895  av_packet_ref(pkt, spare->m_pkt);
1896  //pkt->data is a newly malloced area
1897 
1898  {
1899  QString fname;
1900 #ifdef SPEW_FILES
1901  static int ins_count = 0;
1902  fname = (VERBOSE_LEVEL_CHECK(VB_PROCESS, LOG_ANY) ?
1903  (QString("ins%1").arg(ins_count++)) : QString());
1904 #endif
1905 
1906  if (BuildFrame(pkt, fname))
1907  {
1908  av_packet_free(&pkt);
1909  return -1;
1910  }
1911 
1912  LOG(VB_GENERAL, LOG_INFO,
1913  QString("Inserting %1 I-Frames after #%2 %3")
1914  .arg((int)(deltaPTS / ptsIncrement))
1915  .arg(GetFrameNum(spare)).arg(fname));
1916  }
1917 
1918  inc2x33(&pkt->pts, ptsIncrement * GetNbFields(spare) / 2 + initPTS);
1919 
1920  index = m_vFrame.indexOf(spare) + 1;
1921  while (index < m_vFrame.count() &&
1922  GetFrameTypeT(m_vFrame.at(index)) == 'B')
1923  spare = m_vFrame.at(index++);
1924 
1925  index = m_vFrame.indexOf(spare);
1926 
1927  while (deltaPTS > 0)
1928  {
1929  index++;
1930  increment++;
1931  pkt->dts = pkt->pts;
1932  SetFrameNum(pkt->data, ++frameNum);
1933  MPEG2frame *tmpFrame = GetPoolFrame(pkt);
1934  if (tmpFrame == nullptr)
1935  return -1;
1936  m_vFrame.insert(index, tmpFrame);
1937  ProcessVideo(tmpFrame, m_headerDecoder); //process new frame
1938 
1939  inc2x33(&pkt->pts, ptsIncrement);
1940  deltaPTS -= ptsIncrement;
1941  }
1942 
1943  av_packet_free(&pkt);
1944  // update frame # for all later frames in this group
1945  index++;
1946  RenumberFrames(index, increment);
1947 
1948  return increment;
1949 }
1950 
1951 void MPEG2fixup::AddRangeList(const QStringList& rangelist, int type)
1952 {
1953  frm_dir_map_t *mapPtr = nullptr;
1954 
1955  if (type == MPF_TYPE_CUTLIST)
1956  {
1957  mapPtr = &m_delMap;
1958  m_discard = false;
1959  }
1960  else
1961  mapPtr = &m_saveMap;
1962 
1963  mapPtr->clear();
1964 
1965  for (const auto & range : qAsConst(rangelist))
1966  {
1967  QStringList tmp = range.split(" - ");
1968  if (tmp.size() < 2)
1969  continue;
1970 
1971  std::array<bool,2> ok { false, false };
1972 
1973  long long start = tmp[0].toLongLong(ok.data());
1974  long long end = tmp[1].toLongLong(&ok[1]);
1975 
1976  if (ok[0] && ok[1])
1977  {
1978  if (start == 0)
1979  {
1980  if (type == MPF_TYPE_CUTLIST)
1981  m_discard = true;
1982  }
1983  else
1984  mapPtr->insert(start - 1, MARK_CUT_START);
1985 
1986  mapPtr->insert(end, MARK_CUT_END);
1987  }
1988  }
1989 
1990  if (!rangelist.isEmpty())
1991  m_useSecondary = true;
1992 }
1993 
1994 void MPEG2fixup::ShowRangeMap(frm_dir_map_t *mapPtr, QString msg)
1995 {
1996  if (!mapPtr->isEmpty())
1997  {
1998  int64_t start = 0;
1999  frm_dir_map_t::iterator it = mapPtr->begin();
2000  for (; it != mapPtr->end(); ++it)
2001  {
2002  if (*it == MARK_CUT_END)
2003  msg += QString("\n\t\t%1 - %2").arg(start).arg(it.key());
2004  else
2005  start = it.key();
2006  }
2007  if (*(--it) == MARK_CUT_START)
2008  msg += QString("\n\t\t%1 - end").arg(start);
2009  LOG(VB_PROCESS, LOG_INFO, msg);
2010  }
2011 }
2012 
2014 {
2015  FrameList Lreorder;
2016  int maxPos = dtsOrder->count() - 1;
2017 
2018  if (pos >= maxPos)
2019  return Lreorder;
2020 
2021  MPEG2frame *frame = dtsOrder->at(pos);
2022 
2023  for (pos++; pos < maxPos && GetFrameTypeT(dtsOrder->at(pos)) == 'B'; pos++)
2024  Lreorder.append(dtsOrder->at(pos));
2025 
2026  Lreorder.append(frame);
2027  return Lreorder;
2028 }
2029 
2030 void MPEG2fixup::InitialPTSFixup(MPEG2frame *curFrame, int64_t &origvPTS,
2031  int64_t &PTSdiscrep, int numframes, bool fix) const
2032 {
2033  int64_t tmpPTS = diff2x33(curFrame->m_pkt->pts,
2034  origvPTS / 300);
2035 
2036  if (curFrame->m_pkt->pts == AV_NOPTS_VALUE)
2037  {
2038  LOG(VB_PROCESS, LOG_INFO,
2039  QString("Found frame %1 with missing PTS at %2")
2040  .arg(GetFrameNum(curFrame))
2041  .arg(PtsTime(origvPTS / 300)));
2042  if (fix)
2043  curFrame->m_pkt->pts = origvPTS / 300;
2044  else
2045  PTSdiscrep = AV_NOPTS_VALUE;
2046  }
2047  else if (tmpPTS < -m_ptsIncrement ||
2048  tmpPTS > m_ptsIncrement*numframes)
2049  {
2050  if (tmpPTS != PTSdiscrep)
2051  {
2052  PTSdiscrep = tmpPTS;
2053  LOG(VB_PROCESS, LOG_INFO,
2054  QString("Found invalid PTS (off by %1) at %2")
2055  .arg(PtsTime(tmpPTS),
2056  PtsTime(origvPTS / 300)));
2057  }
2058  if (fix)
2059  curFrame->m_pkt->pts = origvPTS / 300;
2060  }
2061  else
2062  {
2063  origvPTS = curFrame->m_pkt->pts * 300;
2064  }
2065  ptsinc((uint64_t *)&origvPTS,
2066  (uint64_t)(150 * m_ptsIncrement * GetNbFields(curFrame)));
2067 }
2068 
2070 {
2071  LOG(VB_GENERAL, LOG_INFO, "=========================================");
2072  LOG(VB_GENERAL, LOG_INFO, QString("List contains %1 items")
2073  .arg(list->count()));
2074 
2075  for (auto *curFrame : qAsConst(*list))
2076  {
2077  LOG(VB_GENERAL, LOG_INFO,
2078  QString("VID: %1 #:%2 nb: %3 pts: %4 dts: %5 pos: %6")
2079  .arg(GetFrameTypeT(curFrame))
2080  .arg(GetFrameNum(curFrame))
2081  .arg(GetNbFields(curFrame))
2082  .arg(PtsTime(curFrame->m_pkt->pts),
2083  PtsTime(curFrame->m_pkt->dts),
2084  QString::number(curFrame->m_pkt->pos)));
2085  }
2086  LOG(VB_GENERAL, LOG_INFO, "=========================================");
2087 }
2088 
2090 {
2091  // NOTE: expectedvPTS/DTS are in units of SCR (300*PTS) to allow for better
2092  // accounting of rounding errors (still won't be right, but better)
2093  int64_t lastPTS = 0;
2094  int64_t deltaPTS = 0;
2095  std::array<int64_t,N_AUDIO> origaPTS {};
2096  int64_t cutStartPTS = 0;
2097  int64_t cutEndPTS = 0;
2098  uint64_t frame_count = 0;
2099  int new_discard_state = 0;
2100  QMap<int, int> af_dlta_cnt;
2101  QMap<int, int> cutState;
2102 
2103  AVPacket *pkt = av_packet_alloc();
2104  AVPacket *lastRealvPkt = av_packet_alloc();
2105  if ((pkt == nullptr) || (lastRealvPkt == nullptr))
2106  {
2107  LOG(VB_GENERAL, LOG_ERR, "packet allocation failed");
2108  return GENERIC_EXIT_NOT_OK;
2109  }
2110 
2111  if (!InitAV(m_infile, m_format, 0))
2112  {
2113  av_packet_free(&pkt);
2114  av_packet_free(&lastRealvPkt);
2115  return GENERIC_EXIT_NOT_OK;
2116  }
2117 
2118  if (!FindStart())
2119  {
2120  av_packet_free(&pkt);
2121  av_packet_free(&lastRealvPkt);
2122  return GENERIC_EXIT_NOT_OK;
2123  }
2124 
2125  m_ptsIncrement = m_vFrame.first()->m_mpeg2_seq.frame_period / 300;
2126 
2127  int64_t initPTS = m_vFrame.first()->m_pkt->pts;
2128 
2129  LOG(VB_GENERAL, LOG_INFO, QString("#%1 PTS:%2 Delta: 0.0ms queue: %3")
2130  .arg(m_vidId).arg(PtsTime(m_vFrame.first()->m_pkt->pts))
2131  .arg(m_vFrame.count()));
2132 
2133  for (auto it = m_aFrame.begin(); it != m_aFrame.end(); it++)
2134  {
2135  FrameList *af = (*it);
2136  deltaPTS = diff2x33(m_vFrame.first()->m_pkt->pts, af->first()->m_pkt->pts);
2137  LOG(VB_GENERAL, LOG_INFO,
2138  QString("#%1 PTS:%2 Delta: %3ms queue: %4")
2139  .arg(it.key()) .arg(PtsTime(af->first()->m_pkt->pts))
2140  .arg(1000.0*deltaPTS / 90000.0).arg(af->count()));
2141 
2142  if (cmp2x33(af->first()->m_pkt->pts, initPTS) < 0)
2143  initPTS = af->first()->m_pkt->pts;
2144  }
2145 
2146  initPTS -= 16200; //0.18 seconds back to prevent underflow
2147 
2148  PTSOffsetQueue poq(m_vidId, m_aFrame.keys(), initPTS);
2149 
2150  LOG(VB_PROCESS, LOG_INFO,
2151  QString("ptsIncrement: %1 Frame #: %2 PTS-adjust: %3")
2152  .arg(m_ptsIncrement).arg(GetFrameNum(m_vFrame.first()))
2153  .arg(PtsTime(initPTS)));
2154 
2155 
2156  int64_t origvPTS = 300 * udiff2x33(m_vFrame.first()->m_pkt->pts,
2157  m_ptsIncrement * GetFrameNum(m_vFrame.first()));
2158  int64_t expectedvPTS = 300 * (udiff2x33(m_vFrame.first()->m_pkt->pts, initPTS) -
2159  (m_ptsIncrement * GetFrameNum(m_vFrame.first())));
2160  int64_t expectedDTS = expectedvPTS - 300 * m_ptsIncrement;
2161 
2162  if (m_discard)
2163  {
2164  cutStartPTS = origvPTS / 300;
2165  }
2166 
2167  for (auto it = m_aFrame.begin(); it != m_aFrame.end(); it++)
2168  {
2169  FrameList *af = (*it);
2170  origaPTS[it.key()] = af->first()->m_pkt->pts * 300;
2171  //expectedPTS[it.key()] = udiff2x33(af->first()->m_pkt->pts, initPTS);
2172  af_dlta_cnt[it.key()] = 0;
2173  cutState[it.key()] = static_cast<int>(m_discard);
2174  }
2175 
2176  ShowRangeMap(&m_delMap, "Cutlist:");
2177  ShowRangeMap(&m_saveMap, "Same Range:");
2178 
2179  InitReplex();
2180 
2181  while (!m_fileEnd)
2182  {
2183  /* read packet */
2184  int ret = GetFrame(pkt);
2185  if (ret < 0)
2186  {
2187  av_packet_free(&pkt);
2188  av_packet_free(&lastRealvPkt);
2189  return ret;
2190  }
2191 
2192  if (!m_vFrame.isEmpty() && (m_fileEnd || m_vFrame.last()->m_isSequence))
2193  {
2194  m_displayFrame = 0;
2195 
2196  // since we might reorder the frames when coming out of a cutpoint
2197  // me need to save the first frame here, as it is guaranteed to
2198  // have a sequence header.
2199  MPEG2frame *seqFrame = m_vFrame.first();
2200 
2201  if (!seqFrame->m_isSequence)
2202  {
2203  LOG(VB_GENERAL, LOG_WARNING,
2204  QString("Problem: Frame %1 (type %2) doesn't contain "
2205  "sequence header!")
2206  .arg(frame_count) .arg(GetFrameTypeT(seqFrame)));
2207  }
2208 
2209  if (m_ptsIncrement != seqFrame->m_mpeg2_seq.frame_period / 300)
2210  {
2211  LOG(VB_GENERAL, LOG_WARNING,
2212  QString("WARNING - Unsupported FPS change from %1 to %2")
2213  .arg(90000.0 / m_ptsIncrement, 0, 'f', 2)
2214  .arg(27000000.0 / seqFrame->m_mpeg2_seq.frame_period,
2215  0, 'f', 2));
2216  }
2217 
2218  for (int frame_pos = 0; frame_pos < m_vFrame.count() - 1;)
2219  {
2220  bool ptsorder_eq_dtsorder = false;
2221  int64_t PTSdiscrep = 0;
2222  FrameList Lreorder;
2223  MPEG2frame *markedFrame = nullptr;
2224  MPEG2frame *markedFrameP = nullptr;
2225 
2226  if (expectedvPTS != expectedDTS + m_ptsIncrement * 300)
2227  {
2228  LOG(VB_GENERAL, LOG_ERR,
2229  QString("expectedPTS != expectedDTS + ptsIncrement"));
2230  LOG(VB_GENERAL, LOG_ERR, QString("%1 != %2 + %3")
2231  .arg(PtsTime(expectedvPTS / 300),
2232  PtsTime(expectedDTS / 300),
2234  LOG(VB_GENERAL, LOG_ERR, QString("%1 != %2 + %3")
2235  .arg(expectedvPTS)
2236  .arg(expectedDTS)
2237  .arg(m_ptsIncrement));
2238  av_packet_free(&pkt);
2239  av_packet_free(&lastRealvPkt);
2240  return GENERIC_EXIT_NOT_OK;
2241  }
2242 
2243  //reorder frames in presentation order (to the next I/P frame)
2244  Lreorder = ReorderDTStoPTS(&m_vFrame, frame_pos);
2245 
2246  //First pass at fixing PTS values (fixes gross errors only)
2247  for (auto *curFrame : qAsConst(Lreorder))
2248  {
2249  poq.UpdateOrigPTS(m_vidId, origvPTS, curFrame->m_pkt);
2250  InitialPTSFixup(curFrame, origvPTS, PTSdiscrep,
2251  m_maxFrames, true);
2252  }
2253 
2254  // if there was a PTS jump, find the largest change
2255  // in the next x frames
2256  // At the end of this, vFrame should look just like it did
2257  // beforehand
2258  if (PTSdiscrep && !m_fileEnd)
2259  {
2260  int pos = m_vFrame.count();
2261  int count = Lreorder.count();
2262  while (m_vFrame.count() - frame_pos - count < 20 && !m_fileEnd)
2263  {
2264  if ((ret = GetFrame(pkt)) < 0)
2265  {
2266  av_packet_free(&pkt);
2267  av_packet_free(&lastRealvPkt);
2268  return ret;
2269  }
2270  }
2271 
2272  if (!m_fileEnd)
2273  {
2274  int64_t tmp_origvPTS = origvPTS;
2275  int numframes = (m_maxFrames > 1) ? m_maxFrames - 1 : 1;
2276  bool done = false;
2277  while (!done &&
2278  (frame_pos + count + 1) < m_vFrame.count())
2279  {
2280  FrameList tmpReorder;
2281  tmpReorder = ReorderDTStoPTS(&m_vFrame,
2282  frame_pos + count);
2283  for (auto *curFrame : qAsConst(tmpReorder))
2284  {
2285  int64_t tmpPTSdiscrep = 0;
2286  InitialPTSFixup(curFrame, tmp_origvPTS,
2287  tmpPTSdiscrep, numframes, false);
2288  if (!tmpPTSdiscrep)
2289  {
2290  //discrepancy was short-lived, continue on
2291  done = true;
2292  PTSdiscrep = 0;
2293  break;
2294  }
2295  if (tmpPTSdiscrep != AV_NOPTS_VALUE &&
2296  tmpPTSdiscrep != PTSdiscrep)
2297  PTSdiscrep = tmpPTSdiscrep;
2298  }
2299  count += tmpReorder.count();
2300  }
2301  }
2302 
2303  // push extra read frames onto 'unreadFrames' queue
2304  while (m_vFrame.count() > pos)
2305  {
2306  m_unreadFrames.enqueue(m_vFrame.takeAt(pos));
2307  }
2308  m_fileEnd = false;
2309  }
2310 
2311  //check for cutpoints and convert to I-frames if needed
2312  for (int curIndex = 0; curIndex < Lreorder.count(); curIndex++)
2313  {
2314  MPEG2frame *curFrame = Lreorder.at(curIndex);
2315  if (!m_saveMap.isEmpty())
2316  {
2317  if (m_saveMap.begin().key() <= frame_count)
2318  m_saveMap.remove(m_saveMap.begin().key());
2319  if (!m_saveMap.empty() && m_saveMap.begin().value() == 0)
2320  {
2321  LOG(VB_GENERAL, LOG_INFO,
2322  QString("Saving frame #%1") .arg(frame_count));
2323 
2324  if (GetFrameTypeT(curFrame) != 'I' &&
2325  ConvertToI(&Lreorder, frame_pos))
2326  {
2327  av_packet_free(&pkt);
2328  av_packet_free(&lastRealvPkt);
2330  }
2331 
2332  WriteFrame(QString("save%1.yuv").arg(frame_count),
2333  curFrame);
2334  }
2335  }
2336 
2337  if (!m_delMap.empty() && m_delMap.begin().key() <= frame_count)
2338  {
2339  new_discard_state = m_delMap.begin().value();
2340  LOG(VB_GENERAL, LOG_INFO,
2341  QString("Del map found %1 at %2 (%3)")
2342  .arg(new_discard_state) .arg(frame_count)
2343  .arg(m_delMap.begin().key()));
2344 
2345  m_delMap.remove(m_delMap.begin().key());
2346  markedFrameP = curFrame;
2347 
2348  if (!new_discard_state)
2349  {
2350  cutEndPTS = markedFrameP->m_pkt->pts;
2351  poq.SetNextPTS(
2352  diff2x33(cutEndPTS, expectedvPTS / 300),
2353  cutEndPTS);
2354  }
2355  else
2356  {
2357  cutStartPTS =
2358  add2x33(markedFrameP->m_pkt->pts,
2359  m_ptsIncrement *
2360  GetNbFields(markedFrameP) / 2);
2361  for (auto it3 = m_aFrame.begin();
2362  it3 != m_aFrame.end(); it3++)
2363  {
2364  cutState[it3.key()] = 1;
2365  }
2366  }
2367 
2368  // Rebuild when 'B' frame, or completing a cut, and the
2369  // marked frame is a 'P' frame.
2370  // After conversion, frames will be in linear order.
2371  if ((GetFrameTypeT(curFrame) == 'B') ||
2372  (!new_discard_state &&
2373  (GetFrameTypeT(curFrame) == 'P')))
2374  {
2375  if (ConvertToI(&Lreorder, frame_pos))
2376  {
2377  av_packet_free(&pkt);
2378  av_packet_free(&lastRealvPkt);
2380  }
2381  ptsorder_eq_dtsorder = true;
2382  }
2383  else if (!new_discard_state &&
2384  GetFrameTypeT(curFrame) == 'I')
2385  {
2386  m_vFrame.move(frame_pos, frame_pos + curIndex);
2387  ptsorder_eq_dtsorder = true;
2388  }
2389 
2390  //convert from presentation-order to decode-order
2391  markedFrame = m_vFrame.at(frame_pos + curIndex);
2392 
2393  if (!new_discard_state)
2394  {
2395  AddSequence(markedFrame, seqFrame);
2396  RenumberFrames(frame_pos + curIndex,
2397  - GetFrameNum(markedFrame));
2398  }
2399  }
2400 
2401  frame_count++;
2402  }
2403 
2404  if (!Lreorder.isEmpty())
2405  {
2406  av_packet_unref(lastRealvPkt);
2407  av_packet_ref(lastRealvPkt, Lreorder.last()->m_pkt);
2408  }
2409 
2410  if (markedFrame || !m_discard)
2411  {
2412  int64_t dtsExtra = 0;
2413  //check for PTS discontinuity
2414  for (auto *curFrame : qAsConst(Lreorder))
2415  {
2416  if (markedFrameP && m_discard)
2417  {
2418  if (curFrame != markedFrameP)
2419  continue;
2420 
2421  markedFrameP = nullptr;
2422  }
2423 
2424  dec2x33(&curFrame->m_pkt->pts,
2425  poq.Get(m_vidId, curFrame->m_pkt));
2426  deltaPTS = diff2x33(curFrame->m_pkt->pts,
2427  expectedvPTS / 300);
2428 
2429  if (deltaPTS < -2 || deltaPTS > 2)
2430  {
2431  LOG(VB_PROCESS, LOG_INFO,
2432  QString("PTS discrepancy: %1 != %2 on "
2433  "%3-Type (%4)")
2434  .arg(curFrame->m_pkt->pts)
2435  .arg(expectedvPTS / 300)
2436  .arg(GetFrameTypeT(curFrame))
2437  .arg(GetFrameNum(curFrame)));
2438  }
2439 
2440  //remove repeat_first_field if necessary
2441  if (m_noRepeat)
2442  SetRepeat(curFrame, 2, false);
2443 
2444  //force PTS to stay in sync (this could be a bad idea!)
2445  if (m_fixPts)
2446  curFrame->m_pkt->pts = expectedvPTS / 300;
2447 
2448  if (deltaPTS > m_ptsIncrement*m_maxFrames)
2449  {
2450  LOG(VB_GENERAL, LOG_NOTICE,
2451  QString("Need to insert %1 frames > max "
2452  "allowed: %2. Assuming bad PTS")
2453  .arg((int)(deltaPTS / m_ptsIncrement))
2454  .arg(m_maxFrames));
2455  curFrame->m_pkt->pts = expectedvPTS / 300;
2456  deltaPTS = 0;
2457  }
2458 
2459  lastPTS = expectedvPTS;
2460  expectedvPTS += 150 * m_ptsIncrement *
2461  GetNbFields(curFrame);
2462 
2463  if (curFrame == markedFrameP && new_discard_state)
2464  break;
2465  }
2466 
2467  // dtsExtra is applied at the end of this block if the
2468  // current tail has repeat_first_field set
2469  if (ptsorder_eq_dtsorder)
2470  dtsExtra = 0;
2471  else
2472  dtsExtra = 150 * m_ptsIncrement *
2473  (GetNbFields(m_vFrame.at(frame_pos)) - 2);
2474 
2475  if (!markedFrame && deltaPTS > (4 * m_ptsIncrement / 5))
2476  {
2477  // if we are off by more than 1/2 frame, it is time to
2478  // add a frame
2479  // The frame(s) will be added right after lVpkt_tail,
2480  // and lVpkt_head will be adjusted accordingly
2481 
2482  m_vFrame.at(frame_pos)->m_pkt->pts = lastPTS / 300;
2483  ret = InsertFrame(GetFrameNum(m_vFrame.at(frame_pos)),
2484  deltaPTS, m_ptsIncrement, 0);
2485 
2486  if (ret < 0)
2487  {
2488  av_packet_free(&pkt);
2489  av_packet_free(&lastRealvPkt);
2491  }
2492 
2493  for (int index = frame_pos + Lreorder.count();
2494  ret && index < m_vFrame.count(); index++, --ret)
2495  {
2496  lastPTS = expectedvPTS;
2497  expectedvPTS += 150 * m_ptsIncrement *
2498  GetNbFields(m_vFrame.at(index));
2499  Lreorder.append(m_vFrame.at(index));
2500  }
2501  }
2502 
2503  // Set DTS (ignore any current values), and send frame to
2504  // multiplexer
2505 
2506  for (int i = 0; i < Lreorder.count(); i++, frame_pos++)
2507  {
2508  MPEG2frame *curFrame = m_vFrame.at(frame_pos);
2509  if (m_discard)
2510  {
2511  if (curFrame != markedFrame)
2512  continue;
2513 
2514  m_discard = false;
2515  markedFrame = nullptr;
2516  }
2517 
2518  // Make clang-tidy null dereference checker happy.
2519  if (curFrame == nullptr)
2520  continue;
2521  curFrame->m_pkt->dts = (expectedDTS / 300);
2522 #if 0
2523  if (GetFrameTypeT(curFrame) == 'B')
2524  curFrame->m_pkt->pts = (expectedDTS / 300);
2525 #endif
2526  expectedDTS += 150 * m_ptsIncrement *
2527  ((!ptsorder_eq_dtsorder && i == 0) ? 2 :
2528  GetNbFields(curFrame));
2529  LOG(VB_FRAME, LOG_INFO,
2530  QString("VID: %1 #:%2 nb: %3 pts: %4 dts: %5 "
2531  "pos: %6")
2532  .arg(GetFrameTypeT(curFrame))
2533  .arg(GetFrameNum(curFrame))
2534  .arg(GetNbFields(curFrame))
2535  .arg(PtsTime(curFrame->m_pkt->pts),
2536  PtsTime(curFrame->m_pkt->dts),
2537  QString::number(curFrame->m_pkt->pos)));
2538  if (AddFrame(curFrame))
2539  {
2540  av_packet_free(&pkt);
2541  av_packet_free(&lastRealvPkt);
2542  return GENERIC_EXIT_DEADLOCK;
2543  }
2544 
2545  if (curFrame == markedFrame)
2546  {
2547  markedFrame = nullptr;
2548  m_discard = true;
2549  }
2550  }
2551 
2552  expectedDTS += dtsExtra;
2553  }
2554  else
2555  {
2556  frame_pos += Lreorder.count();
2557  }
2558  if (PTSdiscrep)
2559  poq.SetNextPos(add2x33(poq.Get(m_vidId, lastRealvPkt),
2560  PTSdiscrep), lastRealvPkt);
2561  }
2562 
2563  if (m_discard)
2564  cutEndPTS = lastRealvPkt->pts;
2565 
2566  if (m_fileEnd)
2567  m_useSecondary = false;
2568  if (m_vFrame.count() > 1 || m_fileEnd)
2569  StoreSecondary();
2570  }
2571 
2572  for (auto it = m_aFrame.begin(); it != m_aFrame.end(); it++)
2573  {
2574  FrameList *af = (*it);
2575  AVCodecContext *CC = getCodecContext(it.key());
2576  AVCodecParserContext *CPC = getCodecParserContext(it.key());
2577  bool backwardsPTS = false;
2578 
2579  while (!af->isEmpty())
2580  {
2581  if (!CC || !CPC)
2582  {
2583  m_framePool.enqueue(af->takeFirst());
2584  continue;
2585  }
2586  // What to do if the CC is corrupt?
2587  // Just wait and hope it repairs itself
2588  if (CC->sample_rate == 0 || !CPC || CPC->duration == 0)
2589  break;
2590 
2591  // The order of processing frames is critical to making
2592  // everything work. Backwards PTS discrepancies complicate
2593  // the processing significantly
2594  // Processing works as follows:
2595  // detect whether there is a discontinuous PTS (tmpPTS != 0)
2596  // in the audio stream only.
2597  // next check if a cutpoint is active, and discard frames
2598  // as needed
2599  // next check that the current PTS < last video PTS
2600  // if we get this far, update the expected PTS, and write out
2601  // the audio frame
2602  int64_t incPTS =
2603  90000LL * (int64_t)CPC->duration / CC->sample_rate;
2604 
2605  if (poq.UpdateOrigPTS(it.key(), origaPTS[it.key()],
2606  af->first()->m_pkt) < 0)
2607  {
2608  backwardsPTS = true;
2609  af_dlta_cnt[it.key()] = 0;
2610  }
2611 
2612  int64_t tmpPTS = diff2x33(af->first()->m_pkt->pts,
2613  origaPTS[it.key()] / 300);
2614 
2615  if (tmpPTS < -incPTS)
2616  {
2617 #ifdef DEBUG_AUDIO
2618  LOG(VB_PROCESS, LOG_INFO,
2619  QString("Aud discard: PTS %1 < %2")
2620  .arg(PtsTime(af->first()->m_pkt->pts))
2621  .arg(PtsTime(origaPTS[it.key()] / 300)));
2622 #endif
2623  m_framePool.enqueue(af->takeFirst());
2624  af_dlta_cnt[it.key()] = 0;
2625  continue;
2626  }
2627 
2628  if (tmpPTS > incPTS * m_maxFrames)
2629  {
2630  LOG(VB_PROCESS, LOG_INFO,
2631  QString("Found invalid audio PTS (off by %1) at %2")
2632  .arg(PtsTime(tmpPTS),
2633  PtsTime(origaPTS[it.key()] / 300)));
2634  if (backwardsPTS && tmpPTS < 90000LL)
2635  {
2636  //there are missing audio frames
2637  LOG(VB_PROCESS, LOG_INFO,
2638  "Fixing missing audio frames");
2639  ptsinc((uint64_t *)&origaPTS[it.key()], 300 * tmpPTS);
2640  backwardsPTS = false;
2641  }
2642  else if (tmpPTS < 90000LL * 4) // 4 seconds
2643  {
2644  if (af_dlta_cnt[it.key()] >= 20)
2645  {
2646  //If there are 20 consecutive frames with an
2647  //offset < 4sec, assume a mismatch and correct.
2648  //Note: if we allow too much discrepancy,
2649  //we could overrun the video queue
2650  ptsinc((uint64_t *)&origaPTS[it.key()],
2651  300 * tmpPTS);
2652  af_dlta_cnt[it.key()] = 0;
2653  }
2654  else
2655  af_dlta_cnt[it.key()]++;
2656  }
2657  af->first()->m_pkt->pts = origaPTS[it.key()] / 300;
2658  }
2659  else if (tmpPTS > incPTS) //correct for small discrepancies
2660  {
2661  incPTS += incPTS;
2662  backwardsPTS = false;
2663  af_dlta_cnt[it.key()] = 0;
2664  }
2665  else
2666  {
2667  backwardsPTS = false;
2668  af_dlta_cnt[it.key()] = 0;
2669  }
2670 
2671  int64_t nextPTS = add2x33(af->first()->m_pkt->pts,
2672  90000LL * (int64_t)CPC->duration / CC->sample_rate);
2673 
2674  if ((cutState[it.key()] == 1 &&
2675  cmp2x33(nextPTS, cutStartPTS) > 0) ||
2676  (cutState[it.key()] == 2 &&
2677  cmp2x33(af->first()->m_pkt->pts, cutEndPTS) < 0))
2678  {
2679 #ifdef DEBUG_AUDIO
2680  LOG(VB_PROCESS, LOG_INFO,
2681  QString("Aud in cutpoint: %1 > %2 && %3 < %4")
2682  .arg(PtsTime(nextPTS)).arg(PtsTime(cutStartPTS))
2683  .arg(PtsTime(af->first()->m_pkt->pts))
2684  .arg(PtsTime(cutEndPTS)));
2685 #endif
2686  m_framePool.enqueue(af->takeFirst());
2687  cutState[it.key()] = 2;
2688  ptsinc((uint64_t *)&origaPTS[it.key()], incPTS * 300);
2689  continue;
2690  }
2691 
2692  int64_t deltaPTS2 = poq.Get(it.key(), af->first()->m_pkt);
2693 
2694  if (udiff2x33(nextPTS, deltaPTS2) * 300 > expectedDTS &&
2695  cutState[it.key()] != 1)
2696  {
2697 #ifdef DEBUG_AUDIO
2698  LOG(VB_PROCESS, LOG_INFO, QString("Aud not ready: %1 > %2")
2699  .arg(PtsTime(udiff2x33(nextPTS, deltaPTS2)))
2700  .arg(PtsTime(expectedDTS / 300)));
2701 #endif
2702  break;
2703  }
2704 
2705  if (cutState[it.key()] == 2)
2706  cutState[it.key()] = 0;
2707 
2708  ptsinc((uint64_t *)&origaPTS[it.key()], incPTS * 300);
2709 
2710  dec2x33(&af->first()->m_pkt->pts, deltaPTS2);
2711 
2712 #if 0
2713  expectedPTS[it.key()] = udiff2x33(nextPTS, initPTS);
2714  write_audio(lApkt_tail->m_pkt, initPTS);
2715 #endif
2716  LOG(VB_FRAME, LOG_INFO, QString("AUD #%1: pts: %2 pos: %3")
2717  .arg(it.key())
2718  .arg(PtsTime(af->first()->m_pkt->pts))
2719  .arg(af->first()->m_pkt->pos));
2720  if (AddFrame(af->first()))
2721  {
2722  av_packet_free(&pkt);
2723  av_packet_free(&lastRealvPkt);
2724  return GENERIC_EXIT_DEADLOCK;
2725  }
2726  m_framePool.enqueue(af->takeFirst());
2727  }
2728  }
2729  }
2730 
2731  m_rx.m_done = 1;
2732  pthread_mutex_lock( &m_rx.m_mutex );
2733  pthread_cond_signal(&m_rx.m_cond);
2734  pthread_mutex_unlock( &m_rx.m_mutex );
2735  int ex = REENCODE_OK;
2736  void *errors = nullptr; // mythtv#244: return error if any write or close failures
2737  pthread_join(m_thread, &errors);
2738  if (*(int *)errors) {
2739  LOG(VB_GENERAL, LOG_ERR,
2740  QString("joined thread failed with %1 write errors")
2741  .arg(*(int *)errors));
2742  ex = REENCODE_ERROR;
2743  }
2744 
2745  av_packet_free(&pkt);
2746  av_packet_free(&lastRealvPkt);
2747  avformat_close_input(&m_inputFC);
2748  m_inputFC = nullptr;
2749  return ex;
2750 }
2751 
2752 #ifdef NO_MYTH
2753 int verboseMask = VB_GENERAL;
2754 
2755 void usage(char *s)
2756 {
2757  fprintf(stderr, "%s usage:\n", s);
2758  fprintf(stderr, "\t--infile <file> -i <file> : Input mpg file\n");
2759  fprintf(stderr, "\t--outfile <file> -o <file> : Output mpg file\n");
2760  fprintf(stderr, "\t--dbg_lvl # -d # : Debug level\n");
2761  fprintf(stderr, "\t--maxframes # -m # : Max frames to insert at once (default=10)\n");
2762  fprintf(stderr, "\t--cutlist \"start - end\" -c : Apply a cutlist. Specify on e'-c' per cut\n");
2763  fprintf(stderr, "\t--no3to2 -t : Remove 3:2 pullup\n");
2764  fprintf(stderr, "\t--fixup -f : make PTS continuous\n");
2765  fprintf(stderr, "\t--ostream <dvd|ps> -e : Output stream type (defaults to ps)\n");
2766  fprintf(stderr, "\t--showprogress -p : show progress\n");
2767  fprintf(stderr, "\t--help -h : This screen\n");
2768  exit(0);
2769 }
2770 
2771 int main(int argc, char **argv)
2772 {
2773  QStringList cutlist;
2774  QStringList savelist;
2775  char *infile = nullptr, *outfile = nullptr, *format = nullptr;
2776  int no_repeat = 0, fix_PTS = 0, max_frames = 20, otype = REPLEX_MPEG2;
2777  bool showprogress = 0;
2778  const struct option long_options[] =
2779  {
2780  {"infile", required_argument, nullptr, 'i'},
2781  {"outfile", required_argument, nullptr, 'o'},
2782  {"format", required_argument, nullptr, 'r'},
2783  {"dbg_lvl", required_argument, nullptr, 'd'},
2784  {"cutlist", required_argument, nullptr, 'c'},
2785  {"saveframe", required_argument, nullptr, 's'},
2786  {"ostream", required_argument, nullptr, 'e'},
2787  {"no3to2", no_argument, nullptr, 't'},
2788  {"fixup", no_argument, nullptr, 'f'},
2789  {"showprogress", no_argument, nullptr, 'p'},
2790  {"help", no_argument , nullptr, 'h'},
2791  {0, 0, 0, 0}
2792  };
2793 
2794  while (1)
2795  {
2796  int option_index = 0;
2797  char c;
2798  c = getopt_long (argc, argv, "i:o:d:r:m:c:s:e:tfph",
2799  long_options, &option_index);
2800 
2801  if (c == -1)
2802  break;
2803 
2804  switch (c)
2805  {
2806 
2807  case 'i':
2808  infile = optarg;
2809  break;
2810 
2811  case 'o':
2812  outfile = optarg;
2813  break;
2814 
2815  case 'r':
2816  format = optarg;
2817  break;
2818 
2819  case 'e':
2820  if (strlen(optarg) == 3 && strncmp(optarg, "dvd", 3) == 0)
2821  otype = REPLEX_DVD;
2822  break;
2823 
2824  case 'd':
2825  verboseMask = atoi(optarg);
2826  break;
2827 
2828  case 'm':
2829  max_frames = atoi(optarg);
2830  break;
2831 
2832  case 'c':
2833  cutlist.append(optarg);
2834  break;
2835 
2836  case 't':
2837  no_repeat = 1;
2838 
2839  case 'f':
2840  fix_PTS = 1;
2841  break;
2842 
2843  case 's':
2844  savelist.append(optarg);
2845  break;
2846 
2847  case 'p':
2848  showprogress = true;
2849  break;
2850 
2851  case 'h':
2852 
2853  case '?':
2854 
2855  default:
2856  usage(argv[0]);
2857  }
2858  }
2859 
2860  if (infile == nullptr || outfile == nullptr)
2861  usage(argv[0]);
2862 
2863  MPEG2fixup m2f(infile, outfile, nullptr, format,
2864  no_repeat, fix_PTS, max_frames,
2865  showprogress, otype);
2866 
2867  if (cutlist.count())
2868  m2f.AddRangeList(cutlist, MPF_TYPE_CUTLIST);
2869  if (savelist.count())
2870  m2f.AddRangeList(savelist, MPF_TYPE_SAVELIST);
2871  return m2f.Start();
2872 }
2873 #endif
2874 
2876  frm_pos_map_t &posMap,
2877  frm_pos_map_t &durMap)
2878 {
2879  LOG(VB_GENERAL, LOG_INFO, "Generating Keyframe Index");
2880 
2881  int count = 0;
2882 
2883  /*============ initialise AV ===============*/
2884  m_vidId = -1;
2885  if (!InitAV(file, nullptr, 0))
2886  return GENERIC_EXIT_NOT_OK;
2887 
2888  if (m_mkvFile)
2889  {
2890  LOG(VB_GENERAL, LOG_INFO, "Seek tables are not required for MKV");
2891  return GENERIC_EXIT_NOT_OK;
2892  }
2893 
2894  AVPacket *pkt = av_packet_alloc();
2895  if (pkt == nullptr)
2896  {
2897  LOG(VB_GENERAL, LOG_ERR, "packet allocation failed");
2898  return GENERIC_EXIT_NOT_OK;
2899  }
2900 
2901  uint64_t totalDuration = 0;
2902  while (av_read_frame(m_inputFC, pkt) >= 0)
2903  {
2904  if (pkt->stream_index == m_vidId)
2905  {
2906  if (pkt->flags & AV_PKT_FLAG_KEY)
2907  {
2908  posMap[count] = pkt->pos;
2909  durMap[count] = totalDuration;
2910  }
2911 
2912  // XXX totalDuration untested. Results should be the same
2913  // as from mythcommflag --rebuild.
2914 
2915  // totalDuration calculation based on
2916  // AvFormatDecoder::PreProcessVideoPacket()
2917  totalDuration +=
2918  av_q2d(m_inputFC->streams[pkt->stream_index]->time_base) *
2919  pkt->duration * 1000; // msec
2920  count++;
2921  }
2922  av_packet_unref(pkt);
2923  }
2924 
2925  // Close input file
2926  av_packet_free(&pkt);
2927  avformat_close_input(&m_inputFC);
2928  m_inputFC = nullptr;
2929 
2930  LOG(VB_GENERAL, LOG_NOTICE, "Transcode Completed");
2931 
2932  return REENCODE_OK;
2933 }
2934 
2935 /*
2936  * vim:ts=4:sw=4:ai:et:si:sts=4
2937  */
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:1875
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:1135
MPEG2fixup::GetFrameNum
static int GetFrameNum(const MPEG2frame *frame)
Definition: mpeg2fix.h:180
MPEG2fixup::ReorderDTStoPTS
static FrameList ReorderDTStoPTS(FrameList *dtsOrder, int pos)
Definition: mpeg2fix.cpp:2013
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:1700
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:2875
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:1806
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:2069
verboseMask
uint64_t verboseMask
Definition: logging.cpp:97
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:1994
MPEG2fixup::m_noRepeat
bool m_noRepeat
Definition: mpeg2fix.h:249
MPEG2fixup::DecodeToFrame
MPEG2frame * DecodeToFrame(int frameNum, int skip_reset)
Definition: mpeg2fix.cpp:1729
hardwareprofile.smolt.long
long
Definition: smolt.py:76
MAX_FRAMES
static constexpr int MAX_FRAMES
Definition: mpeg2fix.cpp:1352
check_times
void check_times(multiplex_t *mx, int *video_ok, aok_arr &ext_ok, int *start)
Definition: multiplex.cpp:493
REENCODE_OK
@ REENCODE_OK
Definition: transcodedefs.h:7
MPEG2fixup::m_fixPts
bool m_fixPts
Definition: mpeg2fix.h:250
MPEG2frame::m_framePos
uint8_t * m_framePos
Definition: mpeg2fix.h:57
ringbuffer::size
uint32_t size
Definition: ringbuffer.h:42
ring_write
int ring_write(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:90
multiplex_t::error
int error
Definition: multiplex.h:89
GENERIC_EXIT_NOT_OK
@ GENERIC_EXIT_NOT_OK
Exited with error.
Definition: exitcodes.h:12
MPEG2fixup::m_saveMap
frm_dir_map_t m_saveMap
Definition: mpeg2fix.h:233
uint
unsigned int uint
Definition: compat.h:81
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp: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:2030
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:1951
MPEG2fixup::FindStart
bool FindStart()
Definition: mpeg2fix.cpp:1507
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:1390
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:1677
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:1153
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:2089
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:1353
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:1716
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:1688
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:1640