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