MythTV  master
multiplex.cpp
Go to the documentation of this file.
1 #include <cstdlib>
2 #include <cstring>
3 #include <unistd.h>
4 
5 #include "multiplex.h"
6 #include "ts.h"
8 
9 static int buffers_filled(multiplex_t *mx)
10 {
11  int aavail=0;
12  int vavail = ring_avail(mx->index_vrbuffer)/sizeof(index_unit);
13 
14  for (int i=0; i<mx->extcnt;i++) {
15  aavail += ring_avail(&mx->index_extrbuffer[i])/
16  sizeof(index_unit);
17  }
18 
19  if (aavail+vavail) return ((aavail+vavail));
20  return 0;
21 }
22 
23 static int use_video(uint64_t vpts, ext_arr &ext, const aok_arr &aok, int n)
24 {
25  for (int i=0; i < n; i++)
26  if(aok[i] && ptscmp(vpts,ext[i].pts) > 0)
27  return 0;
28  return 1;
29 }
30 static int which_ext(ext_arr &ext, const aok_arr &aok, int n)
31 {
32  int started = 0;
33  int pos = -1;
34  uint64_t tmppts = 0;
35  for (int i=0; i < n; i++) {
36  if(aok[i]){
37  if(! started){
38  started=1;
39  tmppts=ext[i].pts;
40  pos = i;
41  } else if(ptscmp(tmppts, ext[i].pts) > 0) {
42  tmppts = ext[i].pts;
43  pos = i;
44  }
45  }
46  }
47  return pos;
48 }
49 
51 {
52  if (!ring_avail(mx->index_vrbuffer) && mx->finish) return 0;
53 
54  while (ring_avail(mx->index_vrbuffer) < sizeof(index_unit)) {
55  if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
56  LOG(VB_GENERAL, LOG_ERR,
57  "error in peek next video unit");
58  return 0;
59  }
60  }
61 
62  ring_peek(mx->index_vrbuffer, (uint8_t *)viu, sizeof(index_unit),0);
63 #ifdef OUT_DEBUG
64  LOG(VB_GENERAL, LOG_DEBUG,
65  QString("video index start: %1 stop: %2 (%3) rpos: %4\n")
66  .arg(viu->start).arg(viu->start+viu->length)
67  .arg(viu->length).arg(ring_rpos(mx->vrbuffer)));
68 #endif
69 
70  return 1;
71 }
72 
74 {
75  index_unit nviu {};
76  if (!ring_avail(mx->index_vrbuffer) && mx->finish) return 0;
77 
78  while (ring_avail(mx->index_vrbuffer) < sizeof(index_unit)) {
79  if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
80  LOG(VB_GENERAL, LOG_ERR,
81  "error in get next video unit");
82  return 0;
83  }
84  }
85 
86  ring_read(mx->index_vrbuffer, (uint8_t *)viu, sizeof(index_unit));
87 #ifdef OUT_DEBUG
88  LOG(VB_GENERAL, LOG_INFO,
89  QString("video index start: %1 stop: %2 (%3) rpos: %4\n")
90  .arg(viu->start).arg(viu->start+viu->length)
91  .arg(viu->length).arg(ring_rpos(mx->vrbuffer)));
92 #endif
93  if(! peek_next_video_unit(mx, &nviu))
94  return 1;
95  //left-shift by 8 to increase precision
96  viu->ptsrate = (uptsdiff(nviu.dts, viu->dts) << 8) / viu->length;
97  return 1;
98 }
99 
100 static int peek_next_ext_unit(multiplex_t *mx, index_unit *extiu, int i)
101 {
102  if (!ring_avail(&mx->index_extrbuffer[i]) && mx->finish) return 0;
103 
104  while (ring_avail(&mx->index_extrbuffer[i]) < sizeof(index_unit)) {
105  if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
106  LOG(VB_GENERAL, LOG_ERR,
107  "error in peek next video unit");
108  return 0;
109  }
110  }
111 
112  ring_peek(&mx->index_extrbuffer[i], (uint8_t *)extiu,
113  sizeof(index_unit),0);
114 #ifdef OUT_DEBUG
115  LOG(VB_GENERAL, LOG_DEBUG,
116  QString("ext index start: %1 stop: %2 (%3) rpos: %4")
117  .arg(extiu->start).arg(extiu->start+extiu->length)
118  .arg(extiu->length).arg(ring_rpos(mx->extrbuffer)));
119 #endif
120 
121  return 1;
122 }
123 
124 static int get_next_ext_unit(multiplex_t *mx, index_unit *extiu, int i)
125 {
126  index_unit niu {};
127  index_unit *piu = extiu;
128  int length = 0;
129  int j = 0;
130  for(j = 0; j < mx->ext[i].frmperpkt; j++) {
131  if (!ring_avail(&mx->index_extrbuffer[i]) && mx->finish)
132  break;
133 
134  while(ring_avail(&mx->index_extrbuffer[i]) < sizeof(index_unit)) {
135  if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
136  LOG(VB_GENERAL, LOG_ERR,
137  "error in get next ext unit");
138  break;
139  }
140  }
141 
142  ring_read(&mx->index_extrbuffer[i], (uint8_t *)piu,
143  sizeof(index_unit));
144  length += piu->length;
145  piu = &niu;
146  }
147  if (j == 0)
148  return 0;
149  extiu->length = length;
150  extiu->framesize = length;
151  if(! peek_next_ext_unit(mx, &niu, i))
152  return 1;
153  //left-shift by 8 to increase precision
154  extiu->ptsrate = (uptsdiff(niu.pts, extiu->pts) << 8) / extiu->length;
155 
156 #ifdef OUT_DEBUG
157  LOG(VB_GENERAL, LOG_DEBUG,
158  QString("ext index start: %1 stop: %2 (%3) rpos: %4")
159  .arg(extiu->start).arg(extiu->start+extiu->length)
160  .arg(extiu->length).arg(ring_rpos(&mx->extrbuffer[i])));
161 #endif
162  return 1;
163 }
164 
165 static uint8_t get_ptsdts(multiplex_t *mx, index_unit *viu)
166 {
167  uint8_t ptsdts = 0;
168  switch (mx->frame_timestamps){
169  case TIME_ALWAYS:
170  if (viu->frame == I_FRAME || viu->frame == P_FRAME)
171  ptsdts = PTS_DTS;
172  else
173  ptsdts = PTS_ONLY;
174  break;
175 
176  case TIME_IFRAME:
177  if (viu->frame == I_FRAME)
178  ptsdts = PTS_DTS;
179  break;
180  }
181  return ptsdts;
182 }
183 
184 static void writeout_video(multiplex_t *mx)
185 {
186  std::array<uint8_t,3000> outbuf {};
187  int written=0;
188  uint8_t ptsdts=0;
189  int frame_len=0;
190  index_unit *viu = &mx->viu;
191 
192 #ifdef OUT_DEBUG
193  LOG(VB_GENERAL, LOG_DEBUG, "writing VIDEO pack");
194 #endif
195 
196  if(viu->frame_start) {
197  ptsdts = get_ptsdts(mx, viu);
198  frame_len = viu->length;
199  }
200 
201  if (viu->frame_start && viu->seq_header && viu->gop &&
202  viu->frame == I_FRAME){
203  if (!mx->startup && mx->is_ts){
204  write_ts_patpmt(mx->ext.data(), mx->extcnt, 1, outbuf.data());
205  write(mx->fd_out, outbuf.data(), static_cast<size_t>(mx->pack_size)*2);
206  ptsinc(&mx->SCR, mx->SCRinc*2);
207  } else if (!mx->startup && mx->navpack){
208  write_nav_pack(mx->pack_size, mx->extcnt,
209  mx->SCR, mx->muxr, outbuf.data());
210  write(mx->fd_out, outbuf.data(), mx->pack_size);
211  ptsinc(&mx->SCR, mx->SCRinc);
212  } else mx->startup = 0;
213 #ifdef OUT_DEBUG
214  LOG(VB_GENERAL, LOG_DEBUG, " with sequence and gop header");
215 #endif
216  }
217 
218  if (mx->finish != 2 && dummy_space(&mx->vdbuf) < mx->data_size){
219  return;
220  }
221  unsigned int length = viu->length;
222  while (!mx->is_ts && length < mx->data_size){
223  index_unit nviu {};
224  int old_start = viu->frame_start;
225  int old_frame = viu->frame;
226  uint64_t old_pts = viu->pts;
227  uint64_t old_dts = viu->dts;
228  dummy_add(&mx->vdbuf, uptsdiff(viu->dts+mx->video_delay,0)
229  , viu->length);
230  if ( peek_next_video_unit(mx, &nviu)){
231  if (!nviu.seq_header || !nviu.gop ||
232  nviu.frame != I_FRAME){
233  get_next_video_unit(mx, viu);
234  frame_len = viu->length;
235  length += viu->length;
236  if(old_start) {
237  viu->pts = old_pts;
238  viu->dts = old_dts;
239  viu->frame = old_frame;
240  } else {
241  ptsdts = get_ptsdts(mx, viu);
242  }
243  } else break;
244  } else break;
245  }
246 
247  if (viu->frame_start){
248  viu->frame_start=0;
249  if (viu->gop){
250  std::vector<uint8_t> gop(8);
251  frame_len=length-frame_len;
252  ring_peek(mx->vrbuffer, gop, frame_len);
253  pts2time( viu->pts + mx->video_delay, gop.data(), 8);
254  ring_poke(mx->vrbuffer, gop.data(), 8, frame_len);
255  viu->gop=0;
256  }
257  if (mx->VBR) {
258  mx->extra_clock = ptsdiff(viu->dts + mx->video_delay,
259  mx->SCR + 500*CLOCK_MS);
260 #ifdef OUT_DEBUG1
261  LOG(VB_GENERAL, LOG_DEBUG,
262  QString("EXTRACLOCK2: %1 %2 %3")
263  .arg(viu->dts).arg(mx->video_delay).arg(mx->SCR));
264  LOG(VB_GENERAL, LOG_DEBUG, QString("EXTRACLOCK2: %1")
265  .arg(mx->extra_clock));
266  printpts(mx->extra_clock);
267 #endif
268 
269  if (mx->extra_clock < 0)
270  mx->extra_clock = 0.0;
271  }
272  }
273 
274 
275  int nlength = length;
276  if (mx->is_ts) {
277  written = write_video_ts( viu->pts+mx->video_delay,
278  viu->dts+mx->video_delay,
279  mx->SCR, outbuf.data(), &nlength,
280  ptsdts, mx->vrbuffer);
281  } else {
282  written = write_video_pes( mx->pack_size, mx->extcnt,
283  viu->pts+mx->video_delay,
284  viu->dts+mx->video_delay,
285  mx->SCR, mx->muxr, outbuf.data(), &nlength,
286  ptsdts, mx->vrbuffer);
287  }
288 
289  // something bad happened with the PES or TS write, bail
290  if (written == -1)
291  return;
292 
293  length -= nlength;
294  dummy_add(&mx->vdbuf, uptsdiff( viu->dts+mx->video_delay,0)
295  , viu->length-length);
296  viu->length = length;
297 
298  //estimate next pts based on bitrate of this stream and data written
299  viu->dts = uptsdiff(viu->dts + ((nlength*viu->ptsrate)>>8), 0);
300 
301  if (write(mx->fd_out, outbuf.data(), written) != written) {
302  mx->error++;
303  if (mx->error <= 0) mx->error = 1; // avoid int rollover to zero
304  if (mx->error < 10) { // mythtv#244: log only first few failures
305  LOG(VB_GENERAL, LOG_ERR,
306  QString("%1 writes failed: %2")
307  .arg(mx->error).arg(strerror(errno)));
308  }
309  }
310 
311 #ifdef OUT_DEBUG
312  LOG(VB_GENERAL, LOG_DEBUG, "VPTS");
313  printpts(viu->pts);
314  LOG(VB_GENERAL, LOG_DEBUG, " DTS");
315  printpts(viu->dts);
316  printpts(mx->video_delay);
317 #endif
318 
319  if (viu->length == 0){
320  get_next_video_unit(mx, viu);
321  }
322 
323 }
324 
325 static void writeout_ext(multiplex_t *mx, int n)
326 {
327  std::array<uint8_t,3000> outbuf {};
328  int written=0;
329  uint64_t dpts=0;
330  int newpts=0;
331  int nframes=1;
332  int ac3_off=0;
333  int rest_data = 5;
334 
335  int type = mx->ext[n].type;
336  ringbuffer *airbuffer = &mx->index_extrbuffer[n];
337  dummy_buffer *dbuf = &mx->ext[n].dbuf;
338  uint64_t adelay = mx->ext[n].pts_off;
339  uint64_t *apts = &mx->ext[n].pts;
340  index_unit *aiu = &mx->ext[n].iu;
341 
342  switch (type){
343 
344  case MPEG_AUDIO:
345 #ifdef OUT_DEBUG
346  LOG(VB_GENERAL, LOG_DEBUG, QString("writing AUDIO%1 pack\n").arg(n));
347 #endif
348  break;
349 
350  case AC3:
351 #ifdef OUT_DEBUG
352  LOG(VB_GENERAL, LOG_DEBUG, QString("writing AC3%1 pack\n").arg(n));
353 #endif
354  rest_data = 1; // 4 bytes AC3 header
355  break;
356 
357  default:
358  return;
359  }
360 
361  if (mx->finish != 2 && dummy_space(dbuf) < mx->data_size + rest_data){
362  return;
363  }
364 
365  uint64_t pts = uptsdiff( aiu->pts + mx->audio_delay, adelay );
366  *apts = pts;
367  unsigned int length = aiu->length;
368  if (length < aiu->framesize){
369  newpts = 1;
370  ac3_off = length;
371  }
372  dummy_add(dbuf, pts, aiu->length);
373 
374 #ifdef OUT_DEBUG
375  LOG(VB_GENERAL, LOG_DEBUG, QString("start: %1 stop: %2 (%3) length %4")
376  .arg(aiu->start).arg(aiu->start+aiu->length)
377  .arg(aiu->length).arg(length));
378  printpts(*apts);
379  printpts(aiu->pts);
380  printpts(mx->audio_delay);
381  printpts(adelay);
382  printpts(pts);
383 #endif
384  while (!mx->is_ts && length < mx->data_size + rest_data){
385  if (ring_read(airbuffer, (uint8_t *)aiu, sizeof(index_unit)) > 0){
386  dpts = uptsdiff(aiu->pts +mx->audio_delay, adelay );
387 
388  if (newpts){
389  pts = dpts;
390  newpts=0;
391  }
392 
393  length+= aiu->length;
394  if (length < mx->data_size + rest_data)
395  dummy_add(dbuf, dpts, aiu->length);
396 
397  *apts = dpts;
398  nframes++;
399 #ifdef OUT_DEBUG
400  LOG(VB_GENERAL, LOG_DEBUG,
401  QString("start: %1 stop: %2 (%3) length %4")
402  .arg(aiu->start).arg(aiu->start+aiu->length)
403  .arg(aiu->length).arg(length));
404  printpts(*apts);
405  printpts(aiu->pts);
406  printpts(mx->audio_delay);
407  printpts(adelay);
408 #endif
409  } else if (mx->finish){
410  break;
411  } else if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
412  LOG(VB_GENERAL, LOG_ERR, "error in writeout ext");
413  exit(1);
414  }
415  }
416 
417  int nlength = length;
418 
419  switch (type) {
420  case MPEG_AUDIO:
421  if(mx->is_ts) {
422  written = write_audio_ts( mx->ext[n].strmnum, pts,
423  outbuf.data(), &nlength, newpts ? 0 : PTS_ONLY,
424  &mx->extrbuffer[n]);
425  } else {
426  written = write_audio_pes( mx->pack_size, mx->extcnt,
427  mx->ext[n].strmnum, pts, mx->SCR,
428  mx->muxr, outbuf.data(), &nlength, PTS_ONLY,
429  &mx->extrbuffer[n]);
430  }
431  break;
432  case AC3:
433  if(mx->is_ts) {
434  written = write_ac3_ts(mx->ext[n].strmnum, pts,
435  outbuf.data(), &nlength, newpts ? 0 : PTS_ONLY,
436  mx->ext[n].frmperpkt, &mx->extrbuffer[n]);
437  } else {
438  written = write_ac3_pes( mx->pack_size, mx->extcnt,
439  mx->ext[n].strmnum, pts, mx->SCR,
440  mx->muxr, outbuf.data(), &nlength, PTS_ONLY,
441  nframes, ac3_off,
442  &mx->extrbuffer[n]);
443  }
444  break;
445  }
446 
447  // something bad happened when writing TS or PES to the MPEG or AC3
448  // audio stream
449  if (written == -1)
450  return;
451 
452  length -= nlength;
453  write(mx->fd_out, outbuf.data(), written);
454 
455  dummy_add(dbuf, dpts, aiu->length-length);
456  aiu->length = length;
457  aiu->start = ring_rpos(&mx->extrbuffer[n]);
458 
459  if (aiu->length == 0){
460  get_next_ext_unit(mx, aiu, n);
461  } else {
462  //estimate next pts based on bitrate of stream and data written
463  aiu->pts = uptsdiff(aiu->pts + ((nlength*aiu->ptsrate)>>8), 0);
464  }
465  *apts = uptsdiff(aiu->pts + mx->audio_delay, adelay);
466 #ifdef OUT_DEBUG
467  if ((int64_t)*apts < 0)
468  LOG(VB_GENERAL, LOG_DEBUG, "SCHEISS APTS");
469  printpts(*apts);
470  printpts(aiu->pts);
471  printpts(mx->audio_delay);
472  printpts(adelay);
473 #endif
474 
475  if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
476  LOG(VB_GENERAL, LOG_ERR, "error in writeout ext");
477  exit(1);
478  }
479 }
480 
481 static void writeout_padding (multiplex_t *mx)
482 {
483  std::array<uint8_t,3000> outbuf {};
484 #if 0
485  LOG(VB_GENERAL, LOG_INFO, "writing PADDING pack");
486 #endif
487 
488  write_padding_pes( mx->pack_size, mx->extcnt, mx->SCR,
489  mx->muxr, outbuf.data());
490  write(mx->fd_out, outbuf.data(), mx->pack_size);
491 }
492 
493 void check_times( multiplex_t *mx, int *video_ok, aok_arr &ext_ok, int *start)
494 {
495  int set_ok = 0;
496 
497  ext_ok.fill(false);
498  *video_ok = 0;
499 
500  if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
501  LOG(VB_GENERAL, LOG_ERR, "error in get next video unit");
502  return;
503  }
504 
505  /* increase SCR to next packet */
506  mx->oldSCR = mx->SCR;
507  if (!*start){
508  ptsinc(&mx->SCR, mx->SCRinc);
509  } else *start = 0;
510 
511  if (mx->VBR) {
512 #ifdef OUT_DEBUG1
513  LOG(VB_GENERAL, LOG_DEBUG,
514  QString("EXTRACLOCK: %1").arg(mx->extra_clock));
515  printpts(mx->extra_clock);
516 #endif
517 
518  if (mx->extra_clock > 0.0) {
519  int64_t d = mx->extra_clock/ mx->SCRinc - 1;
520  if (d > 0)
521  mx->extra_clock = d*mx->SCRinc;
522  else
523  mx->extra_clock = 0.0;
524  }
525 
526  if (mx->extra_clock > 0.0) {
527  int64_t temp_scr = mx->extra_clock;
528 
529  for (int i=0; i<mx->extcnt; i++){
530  if (ptscmp(mx->SCR + temp_scr + 100*CLOCK_MS,
531  mx->ext[i].iu.pts) > 0) {
532  while (ptscmp(mx->SCR + temp_scr
533  + 100*CLOCK_MS,
534  mx->ext[i].iu.pts) > 0)
535  temp_scr -= mx->SCRinc;
536  temp_scr += mx->SCRinc;
537  }
538  }
539 
540  if (temp_scr > 0.0) {
541  mx->SCR += temp_scr;
542  mx->extra_clock -= temp_scr;
543  } else
544  mx->extra_clock = 0.0;
545  }
546  }
547 
548  /* clear decoder buffers up to SCR */
549  dummy_delete(&mx->vdbuf, mx->SCR);
550 
551  for (int i=0;i <mx->extcnt; i++)
552  dummy_delete(&mx->ext[i].dbuf, mx->SCR);
553 
554  if (dummy_space(&mx->vdbuf) > mx->vsize && mx->viu.length > 0 &&
555  (ptscmp(mx->viu.dts + mx->video_delay, 500*CLOCK_MS +mx->oldSCR)<0)
556  && ring_avail(mx->index_vrbuffer)){
557  *video_ok = 1;
558  set_ok = 1; //NOLINT(clang-analyzer-deadcode.DeadStores)
559  }
560 
561  for (int i = 0; i < mx->extcnt; i++){
562  if (dummy_space(&mx->ext[i].dbuf) > mx->extsize &&
563  mx->ext[i].iu.length > 0 &&
564  ptscmp(mx->ext[i].pts, 500*CLOCK_MS + mx->oldSCR) < 0
565  && ring_avail(&mx->index_extrbuffer[i])){
566  ext_ok[i] = true;
567  set_ok = 1; //NOLINT(clang-analyzer-deadcode.DeadStores)
568  }
569  }
570 #ifdef OUT_DEBUG
571  if (set_ok) {
572  LOG(VB_GENERAL, LOG_DEBUG, "SCR");
573  printpts(mx->oldSCR);
574  LOG(VB_GENERAL, LOG_DEBUG, "VDTS");
575  printpts(mx->viu.dts);
576  LOG(VB_GENERAL, LOG_DEBUG, QString(" (%1) EXT").arg(*video_ok));
577  for (int i = 0; i < mx->extcnt; i++){
578  LOG(VB_GENERAL, LOG_DEBUG,
579  QString("%1:").arg(mx->ext[i].type));
580  printpts(mx->ext[i].pts);
581  LOG(VB_GENERAL, LOG_DEBUG,
582  QString(" (%1)").arg(ext_ok[i]));
583  }
584  }
585 #else
586  (void)set_ok;
587 #endif
588 }
589 
590 int write_out_packs( multiplex_t *mx, int video_ok, aok_arr &ext_ok)
591 {
592  if (video_ok && use_video(mx->viu.dts + mx->video_delay,
593  mx->ext, ext_ok, mx->extcnt)) {
594  writeout_video(mx);
595  } else { // second case(s): audio ok, video in time
596  int i = which_ext(mx->ext, ext_ok, mx->extcnt);
597  int done=0;
598  if(i>=0) {
599  writeout_ext(mx, i);
600  done = 1;
601  }
602  if (!done && !mx->VBR){
603  writeout_padding(mx);
604  }
605  }
606  return mx->error;
607 }
608 
610 {
611  int start=0;
612  int video_ok = 0;
613  aok_arr ext_ok {};
614  int n = 0;
615  std::array<uint8_t,4> mpeg_end { 0x00, 0x00, 0x01, 0xB9 };
616 
617  mx->finish = 1;
618 
619  int old = 0;
620  int nn=0;
621  while ((n=buffers_filled(mx)) && nn<1000 ){
622  if (n== old) nn++;
623  else nn=0;
624  old = n;
625  check_times( mx, &video_ok, ext_ok, &start);
626  write_out_packs( mx, video_ok, ext_ok);
627  }
628 
629  old = 0;nn=0;
630  while ((n=ring_avail(mx->index_vrbuffer)/sizeof(index_unit))
631  && nn<1000){
632  if (n== old) nn++;
633  else nn= 0;
634  old = n;
635  writeout_video(mx);
636  }
637 
638 // flush the rest
639  mx->finish = 2;
640  old = 0;nn=0;
641  for (int i = 0; i < mx->extcnt; i++){
642  while ((n=ring_avail(&mx->index_extrbuffer[i])/
643  sizeof(index_unit)) && nn <100){
644  if (n== old) nn++;
645  else nn = 0;
646  old = n;
647  writeout_ext(mx, i);
648  }
649  }
650 
651  if (mx->otype == REPLEX_MPEG2)
652  write(mx->fd_out, mpeg_end.data(), 4);
653 
654  if (close(mx->fd_out) < 0) {
655  mx->error++; // mythtv#244: close could fail on full disk
656  if (mx->error <= 0) mx->error = 1; // avoid int rollover to zero
657  LOG(VB_GENERAL, LOG_ERR,
658  QString("close failed: %1")
659  .arg(strerror(errno)));
660  }
661 
662  dummy_destroy(&mx->vdbuf);
663  for (int i=0; i<mx->extcnt;i++)
664  dummy_destroy(&mx->ext[i].dbuf);
665  return mx->error;
666 }
667 
668 static int get_ts_video_overhead(int pktsize, sequence_t *seq)
669 {
670  int pktdata = pktsize - TS_HEADER_MIN;
671  uint32_t framesize = seq->bit_rate * 50 / seq->frame_rate; //avg bytes/frame
672  uint32_t numpkt = (framesize + PES_H_MIN + 10 + pktdata -1) / pktdata;
673  return pktsize- ((pktsize * numpkt) - framesize + numpkt - 1) / numpkt;
674 }
675 
676 static int get_ts_ext_overhead(int pktsize, audio_frame_t *extframe,
677  extdata_t *ext, int cnt)
678 {
679  int max = 0;
680  int pktdata = pktsize - TS_HEADER_MIN;
681  for (int i = 0; i < cnt; i++) {
682  // 1/53 is approx 0.15 * 1/8 which allows us to calculate the
683  // # of packets in .15 seconds (which is the number of packets
684  // per PES.
685  ext[i].frmperpkt = extframe[i].bit_rate / 53 /
686  extframe[i].framesize;
687  int size = extframe[i].framesize * ext[i].frmperpkt;
688  int numpkt = (size + pktdata - 1) / pktdata;
689  int overhead = (pktsize * numpkt - size + numpkt - 1) / numpkt;
690  if(overhead > max)
691  max = overhead;
692  }
693  return pktsize - max;
694 }
695 
696 void init_multiplex( multiplex_t *mx, sequence_t *seq_head,
697  audio_frame_t *extframe, int *exttype, const int *exttypcnt,
698  uint64_t video_delay, uint64_t audio_delay, int fd,
699  int (*fill_buffers)(void *p, int f),
700  ringbuffer *vrbuffer, ringbuffer *index_vrbuffer,
701  ringbuffer *extrbuffer, ringbuffer *index_extrbuffer,
702  int otype)
703 {
704  int i = 0;
705  uint32_t data_rate = 0;
706 
707  mx->error = 0; // mythtv#244: added to catch full disk write failures
709  mx->video_delay = video_delay;
710  mx->audio_delay = audio_delay;
711  mx->fd_out = fd;
712  mx->otype = otype;
713 
714  switch(mx->otype){
715 
716  case REPLEX_DVD:
717  mx->video_delay += 180*CLOCK_MS;
718  mx->audio_delay += 180*CLOCK_MS;
719  mx->pack_size = 2048;
720  mx->audio_buffer_size = 4*1024;
721  mx->video_buffer_size = 232*1024;
722  mx->mux_rate = 1260000;
723  mx->navpack = 1;
725  mx->VBR = 1;
726  mx->reset_clocks = 0;
727  mx->write_end_codes = 0;
728  mx->set_broken_link = 0;
729  mx->is_ts = 0;
730  break;
731 
732 
733  case REPLEX_MPEG2:
734  mx->video_delay += 180*CLOCK_MS;
735  mx->audio_delay += 180*CLOCK_MS;
736  mx->pack_size = 2048;
737  mx->audio_buffer_size = 4*1024;
738  mx->video_buffer_size = 224*1024;
739  mx->mux_rate = 0;
740  mx->navpack = 0;
742  mx->VBR = 1;
743  mx->reset_clocks = 1;
744  mx->write_end_codes = 1;
745  mx->set_broken_link = 1;
746  mx->is_ts = 0;
747  break;
748 
749  case REPLEX_HDTV:
750  mx->video_delay += 180*CLOCK_MS;
751  mx->audio_delay += 180*CLOCK_MS;
752  mx->pack_size = 2048;
753  mx->audio_buffer_size = 4*1024;
754  mx->video_buffer_size = 4*224*1024;
755  mx->mux_rate = 0;
756  mx->navpack = 0;
758  mx->VBR = 1;
759  mx->reset_clocks = 1;
760  mx->write_end_codes = 1;
761  mx->set_broken_link = 1;
762  mx->is_ts = 0;
763  break;
764 
765  case REPLEX_TS_SD:
766  mx->video_delay += 180*CLOCK_MS;
767  mx->audio_delay += 180*CLOCK_MS;
768  mx->pack_size = 188;
769  mx->audio_buffer_size = 4*1024;
770  mx->video_buffer_size = 232*1024;
771  mx->mux_rate = 1260000;
772  mx->navpack = 0;
774  mx->VBR = 1;
775  mx->reset_clocks = 0;
776  mx->write_end_codes = 0;
777  mx->set_broken_link = 0;
778  mx->is_ts = 1;
779  break;
780 
781  case REPLEX_TS_HD:
782  mx->video_delay += 180*CLOCK_MS;
783  mx->audio_delay += 180*CLOCK_MS;
784  mx->pack_size = 188;
785  mx->audio_buffer_size = 4*1024;
786  mx->video_buffer_size = 4*224*1024;
787  mx->mux_rate = 0;
788  mx->navpack = 0;
790  mx->VBR = 1;
791  mx->reset_clocks = 0;
792  mx->write_end_codes = 0;
793  mx->set_broken_link = 0;
794  mx->is_ts = 1;
795  break;
796  }
797 
798  for (mx->extcnt = 0, data_rate = 0, i = 0;
799  i < N_AUDIO && exttype[i]; i++){
800  if (exttype[i] >= MAX_TYPES) {
801  LOG(VB_GENERAL, LOG_ERR,
802  QString("Found illegal stream type %1").arg(exttype[i]));
803  exit(1);
804  }
805  mx->ext[i].type = exttype[i];
806  mx->ext[i].pts_off = 0;
807  mx->ext[i].frmperpkt = 1;
808  mx->ext[i].strmnum = exttypcnt[i];
809  strncpy(mx->ext[i].language, extframe[i].language, 4);
810  dummy_init(&mx->ext[i].dbuf, mx->audio_buffer_size);
811  data_rate += extframe[i].bit_rate;
812  mx->extcnt++;
813  }
814 
815  mx->vrbuffer = vrbuffer;
816  mx->index_vrbuffer = index_vrbuffer;
817  mx->extrbuffer = extrbuffer;
818  mx->index_extrbuffer = index_extrbuffer;
819 
821 
822  //NOTE: vpkt_hdr/extpkt_hdr are worst-case for PS streams, but
823  //best-guess for TS streams
824  if(mx->is_ts) {
825  //Use best guess for TS streams
826  mx->data_size = get_ts_video_overhead(mx->pack_size, seq_head);
827  mx->extsize = get_ts_ext_overhead(mx->pack_size, extframe,
828  mx->ext.data(), mx->extcnt);
829 
830  } else {
831  //Use worst case for PS streams
832  mx->data_size = mx->pack_size - PES_H_MIN - PS_HEADER_L1 - 10;
833  mx->extsize = mx->data_size + 5; //one less DTS
834  }
835  mx->vsize = mx->data_size;
836 
837  data_rate += seq_head->bit_rate *400;
838 
839  mx->muxr = ((uint64_t)data_rate / 8 * mx->pack_size) / mx->data_size;
840  // muxrate of payload in Byte/s
841 
842  if (mx->mux_rate) {
843  if ( mx->mux_rate < mx->muxr)
844  LOG(VB_GENERAL, LOG_WARNING,
845  "data rate may be to high for required mux rate");
846  mx->muxr = mx->mux_rate;
847  }
848  LOG(VB_GENERAL, LOG_INFO, QString("Mux rate: %1 Mbit/s")
849  .arg(mx->muxr*8.0/1000000.0, 0,'f',2,QChar('0')));
850 
851  mx->SCRinc = 27000000ULL/((uint64_t)mx->muxr /
852  (uint64_t) mx->pack_size);
853 
854 }
855 
857 {
858  get_next_video_unit(mx, &mx->viu);
859  for (int i=0; i < mx->extcnt; i++)
860  {
861  get_next_ext_unit(mx, &mx->ext[i].iu, i);
862  if (mx->ext[i].type == MPEG_AUDIO || mx->ext[i].type == AC3) {
863  mx->ext[i].pts = uptsdiff(
864  mx->ext[i].iu.pts + mx->audio_delay,
865  mx->ext[i].pts_off);
866  } else {
867  mx->ext[i].pts = uptsdiff(
868  mx->ext[i].iu.pts, mx->ext[i].pts_off);
869  }
870  }
871 
872  mx->SCR = 0;
873 
874  // write first VOBU header
875  if (mx->is_ts) {
876  std::array<uint8_t,2048> outbuf {};
877  write_ts_patpmt(mx->ext.data(), mx->extcnt, 1, outbuf.data());
878  write(mx->fd_out, outbuf.data(), static_cast<size_t>(mx->pack_size)*2);
879  ptsinc(&mx->SCR, mx->SCRinc*2);
880  mx->startup = 1;
881  } else if (mx->navpack){
882  std::array<uint8_t,2048> outbuf {};
883  write_nav_pack(mx->pack_size, mx->extcnt,
884  mx->SCR, mx->muxr, outbuf.data());
885  write(mx->fd_out, outbuf.data(), mx->pack_size);
886  ptsinc(&mx->SCR, mx->SCRinc);
887  mx->startup = 1;
888  } else mx->startup = 0;
889 }
pts2time
void pts2time(uint64_t pts, uint8_t *buf, int len)
Definition: element.cpp:154
index_unit::ptsrate
uint64_t ptsrate
Definition: mpg_common.h:51
get_ts_video_overhead
static int get_ts_video_overhead(int pktsize, sequence_t *seq)
Definition: multiplex.cpp:668
get_next_ext_unit
static int get_next_ext_unit(multiplex_t *mx, index_unit *extiu, int i)
Definition: multiplex.cpp:124
index_unit::frame_start
uint8_t frame_start
Definition: mpg_common.h:48
write_out_packs
int write_out_packs(multiplex_t *mx, int video_ok, aok_arr &ext_ok)
Definition: multiplex.cpp:590
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
peek_next_video_unit
static int peek_next_video_unit(multiplex_t *mx, index_unit *viu)
Definition: multiplex.cpp:50
dummy_init
int dummy_init(dummy_buffer *dbuf, int s)
Definition: ringbuffer.cpp:401
CLOCK_MS
#define CLOCK_MS
Definition: element.h:78
sequence_t::frame_rate
uint32_t frame_rate
Definition: element.h:93
get_ptsdts
static uint8_t get_ptsdts(multiplex_t *mx, index_unit *viu)
Definition: multiplex.cpp:165
multiplex_t::finish
int finish
Definition: multiplex.h:50
fill_buffers
static int fill_buffers(void *r, int finish)
Definition: replex.cpp:1849
multiplex_t::oldSCR
uint64_t oldSCR
Definition: multiplex.h:73
ring_peek
int ring_peek(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:124
dummy_delete
int dummy_delete(dummy_buffer *dbuf, uint64_t time)
Definition: ringbuffer.cpp:444
ringbuffer
Definition: ringbuffer.h:39
multiplex_t::audio_buffer_size
uint32_t audio_buffer_size
Definition: multiplex.h:57
multiplex_t::vrbuffer
ringbuffer * vrbuffer
Definition: multiplex.h:84
sequence_t
Definition: element.h:87
TS_HEADER_MIN
#define TS_HEADER_MIN
Definition: pes.h:12
audio_frame_t::language
char language[4]
Definition: element.h:120
TIME_ALWAYS
#define TIME_ALWAYS
Definition: multiplex.h:62
index_unit::dts
uint64_t dts
Definition: mpg_common.h:40
writeout_video
static void writeout_video(multiplex_t *mx)
Definition: multiplex.cpp:184
multiplex_t::mux_rate
uint32_t mux_rate
Definition: multiplex.h:59
multiplex_t::fd_out
int fd_out
Definition: multiplex.h:42
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
audio_frame_t::bit_rate
uint32_t bit_rate
Definition: element.h:112
multiplex_t::viu
index_unit viu
Definition: multiplex.h:75
write_ts_patpmt
void write_ts_patpmt(extdata_t *ext, int extcnt, uint8_t prog_num, uint8_t *buf)
Definition: ts.cpp:381
REPLEX_TS_HD
#define REPLEX_TS_HD
Definition: multiplex.h:47
write_video_pes
int write_video_pes(int pack_size, int extcnt, uint64_t vpts, uint64_t vdts, uint64_t SCR, uint64_t muxr, uint8_t *buf, int *vlength, uint8_t ptsdts, ringbuffer *vrbuffer)
Definition: pes.cpp:689
ptsinc
static void ptsinc(uint64_t *pts1, uint64_t pts2)
Definition: pes.h:127
printpts
void printpts(int64_t pts)
Definition: pes.cpp:43
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
init_multiplex
void init_multiplex(multiplex_t *mx, sequence_t *seq_head, audio_frame_t *extframe, int *exttype, const int *exttypcnt, uint64_t video_delay, uint64_t audio_delay, int fd, int(*fill_buffers)(void *p, int f), ringbuffer *vrbuffer, ringbuffer *index_vrbuffer, ringbuffer *extrbuffer, ringbuffer *index_extrbuffer, int otype)
Definition: multiplex.cpp:696
sequence_t::bit_rate
uint32_t bit_rate
Definition: element.h:94
REPLEX_HDTV
#define REPLEX_HDTV
Definition: multiplex.h:45
ext_arr
std::array< extdata_t, N_AUDIO > ext_arr
Definition: multiplex.h:38
I_FRAME
#define I_FRAME
Definition: element.h:54
MPEG_AUDIO
@ MPEG_AUDIO
Definition: element.h:84
multiplex_t::navpack
uint8_t navpack
Definition: multiplex.h:61
multiplex_t::otype
int otype
Definition: multiplex.h:48
index_unit::seq_header
uint8_t seq_header
Definition: mpg_common.h:41
close
#define close
Definition: compat.h:43
P_FRAME
#define P_FRAME
Definition: element.h:55
ptsdiff
int64_t ptsdiff(uint64_t pts1, uint64_t pts2)
Definition: pes.cpp:78
writeout_ext
static void writeout_ext(multiplex_t *mx, int n)
Definition: multiplex.cpp:325
PES_H_MIN
#define PES_H_MIN
Definition: pes.h:16
multiplex_t::ext
ext_arr ext
Definition: multiplex.h:79
write_ac3_pes
int write_ac3_pes(int pack_size, int extcnt, int n, uint64_t pts, uint64_t SCR, uint32_t muxr, uint8_t *buf, int *alength, uint8_t ptsdts, int nframes, int ac3_off, ringbuffer *ac3rbuffer)
Definition: pes.cpp:784
multiplex_t::index_extrbuffer
ringbuffer * index_extrbuffer
Definition: multiplex.h:83
mythlogging.h
multiplex_t::write_end_codes
int write_end_codes
Definition: multiplex.h:68
multiplex_t::vsize
unsigned int vsize
Definition: multiplex.h:70
PS_HEADER_L1
#define PS_HEADER_L1
Definition: pes.h:13
hardwareprofile.config.p
p
Definition: config.py:33
index_unit::start
uint32_t start
Definition: mpg_common.h:38
PTS_ONLY
#define PTS_ONLY
Definition: pes.h:46
peek_next_ext_unit
static int peek_next_ext_unit(multiplex_t *mx, index_unit *extiu, int i)
Definition: multiplex.cpp:100
dummy_destroy
void dummy_destroy(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:413
N_AUDIO
#define N_AUDIO
Definition: multiplex.h:35
multiplex_t::index_vrbuffer
ringbuffer * index_vrbuffer
Definition: multiplex.h:85
REPLEX_DVD
#define REPLEX_DVD
Definition: multiplex.h:44
dummy_add
int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
Definition: ringbuffer.cpp:426
multiplex_t::audio_delay
uint64_t audio_delay
Definition: multiplex.h:54
extdata_t
Definition: mpg_common.h:54
multiplex_t::VBR
int VBR
Definition: multiplex.h:65
check_times
void check_times(multiplex_t *mx, int *video_ok, aok_arr &ext_ok, int *start)
Definition: multiplex.cpp:493
multiplex_t::set_broken_link
int set_broken_link
Definition: multiplex.h:69
index_unit::frame
uint8_t frame
Definition: mpg_common.h:45
multiplex_t::SCR
uint64_t SCR
Definition: multiplex.h:72
multiplex_t::error
int error
Definition: multiplex.h:89
extdata_t::frmperpkt
int frmperpkt
Definition: mpg_common.h:60
get_next_video_unit
static int get_next_video_unit(multiplex_t *mx, index_unit *viu)
Definition: multiplex.cpp:73
finish_mpg
int finish_mpg(multiplex_t *mx)
Definition: multiplex.cpp:609
multiplex_t::vdbuf
dummy_buffer vdbuf
Definition: multiplex.h:77
multiplex_t::reset_clocks
int reset_clocks
Definition: multiplex.h:67
which_ext
static int which_ext(ext_arr &ext, const aok_arr &aok, int n)
Definition: multiplex.cpp:30
ring_rpos
static int ring_rpos(ringbuffer *rbuf)
Definition: ringbuffer.h:82
multiplex_t::pack_size
int pack_size
Definition: multiplex.h:55
writeout_padding
static void writeout_padding(multiplex_t *mx)
Definition: multiplex.cpp:481
MAX_TYPES
@ MAX_TYPES
Definition: element.h:84
index_unit::framesize
uint32_t framesize
Definition: mpg_common.h:50
multiplex_t::extra_clock
int64_t extra_clock
Definition: multiplex.h:71
multiplex.h
index_unit::gop
uint8_t gop
Definition: mpg_common.h:43
uptsdiff
uint64_t uptsdiff(uint64_t pts1, uint64_t pts2)
Definition: pes.cpp:104
ring_read
int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:202
AC3
@ AC3
Definition: element.h:84
dummy_buffer
Definition: ringbuffer.h:49
REPLEX_MPEG2
#define REPLEX_MPEG2
Definition: multiplex.h:43
write_padding_pes
void write_padding_pes(int pack_size, int extcnt, uint64_t SCR, uint64_t muxr, uint8_t *buf)
Definition: pes.cpp:677
REPLEX_TS_SD
#define REPLEX_TS_SD
Definition: multiplex.h:46
write_nav_pack
int write_nav_pack(int pack_size, int extcnt, uint64_t SCR, uint32_t muxr, uint8_t *buf)
Definition: pes.cpp:837
use_video
static int use_video(uint64_t vpts, ext_arr &ext, const aok_arr &aok, int n)
Definition: multiplex.cpp:23
multiplex_t::extcnt
int extcnt
Definition: multiplex.h:80
ring_avail
static unsigned int ring_avail(ringbuffer *rbuf)
Definition: ringbuffer.h:108
multiplex_t::fill_buffers
int(* fill_buffers)(void *p, int f)
Definition: multiplex.h:87
write_audio_ts
int write_audio_ts(int n, uint64_t pts, uint8_t *buf, int *alength, uint8_t ptsdts, ringbuffer *arbuffer)
Definition: ts.cpp:288
multiplex_t::startup
int startup
Definition: multiplex.h:49
multiplex_t::muxr
uint32_t muxr
Definition: multiplex.h:60
multiplex_t::data_size
unsigned int data_size
Definition: multiplex.h:56
MThread::exit
void exit(int retcode=0)
Use this to exit from the thread if you are using a Qt event loop.
Definition: mthread.cpp:278
dummy_space
static uint32_t dummy_space(dummy_buffer *dbuf)
Definition: ringbuffer.h:117
multiplex_t::extsize
unsigned int extsize
Definition: multiplex.h:70
mpeg::chrono::pts
std::chrono::duration< CHRONO_TYPE, std::ratio< 1, 90000 > > pts
Definition: mythchrono.h:55
get_ts_ext_overhead
static int get_ts_ext_overhead(int pktsize, audio_frame_t *extframe, extdata_t *ext, int cnt)
Definition: multiplex.cpp:676
setup_multiplex
void setup_multiplex(multiplex_t *mx)
Definition: multiplex.cpp:856
multiplex_t::video_buffer_size
uint32_t video_buffer_size
Definition: multiplex.h:58
write_audio_pes
int write_audio_pes(int pack_size, int extcnt, int n, uint64_t pts, uint64_t SCR, uint32_t muxr, uint8_t *buf, int *alength, uint8_t ptsdts, ringbuffer *arbuffer)
Definition: pes.cpp:739
audio_frame_t::framesize
uint32_t framesize
Definition: element.h:117
ptscmp
int ptscmp(uint64_t pts1, uint64_t pts2)
Definition: pes.cpp:114
audio_frame_t
Definition: element.h:109
ring_poke
int ring_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:163
multiplex_t
Definition: multiplex.h:41
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
write_video_ts
int write_video_ts(uint64_t vpts, uint64_t vdts, uint64_t SCR, uint8_t *buf, int *vlength, uint8_t ptsdts, ringbuffer *vrbuffer)
Definition: ts.cpp:233
PTS_DTS
#define PTS_DTS
Definition: pes.h:47
multiplex_t::priv
void * priv
Definition: multiplex.h:88
index_unit
Definition: mpg_common.h:35
multiplex_t::is_ts
int is_ts
Definition: multiplex.h:66
multiplex_t::video_delay
uint64_t video_delay
Definition: multiplex.h:53
multiplex_t::frame_timestamps
int frame_timestamps
Definition: multiplex.h:64
multiplex_t::extrbuffer
ringbuffer * extrbuffer
Definition: multiplex.h:82
write_ac3_ts
int write_ac3_ts(int n, uint64_t pts, uint8_t *buf, int *alength, uint8_t ptsdts, int nframes, ringbuffer *ac3rbuffer)
Definition: ts.cpp:331
buffers_filled
static int buffers_filled(multiplex_t *mx)
Definition: multiplex.cpp:9
ts.h
index_unit::pts
uint64_t pts
Definition: mpg_common.h:39
multiplex_t::SCRinc
uint64_t SCRinc
Definition: multiplex.h:74
aok_arr
std::array< bool, N_AUDIO > aok_arr
Definition: multiplex.h:39
index_unit::length
uint32_t length
Definition: mpg_common.h:37
TIME_IFRAME
#define TIME_IFRAME
Definition: multiplex.h:63