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