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