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