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