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