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