MythTV  master
multiplex.c
Go to the documentation of this file.
1 #include <unistd.h>
2 #include <string.h>
3 #include <stdlib.h>
4 
5 #include "multiplex.h"
6 #include "ts.h"
7 #include "mythlogging.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, extdata_t *ext, const int *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(extdata_t *ext, const int *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  "video index start: %d stop: %d (%d) rpos: %d\n",
66  viu->start, (viu->start+viu->length),
67  viu->length, 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  "video index start: %d stop: %d (%d) rpos: %d\n",
90  viu->start, (viu->start+viu->length),
91  viu->length, 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  "ext index start: %d stop: %d (%d) rpos: %d",
117  extiu->start, (extiu->start+extiu->length),
118  extiu->length, 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  "ext index start: %d stop: %d (%d) rpos: %d",
159  extiu->start, (extiu->start+extiu->length),
160  extiu->length, 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  uint8_t outbuf[3000];
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, mx->extcnt, 1, outbuf);
205  write(mx->fd_out, outbuf, 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);
210  write(mx->fd_out, outbuf, 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  uint8_t gop[8];
251  frame_len=length-frame_len;
252  ring_peek(mx->vrbuffer, gop, 8, frame_len);
253  pts2time( viu->pts + mx->video_delay, gop, 8);
254  ring_poke(mx->vrbuffer, gop, 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  "EXTRACLOCK2: %lli %lli %lli",
263  viu->dts, mx->video_delay, mx->SCR);
264  LOG(VB_GENERAL, LOG_DEBUG, "EXTRACLOCK2: %lli",
265  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, &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, &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  write(mx->fd_out, outbuf, written);
302 
303 #ifdef OUT_DEBUG
304  LOG(VB_GENERAL, LOG_DEBUG, "VPTS");
305  printpts(viu->pts);
306  LOG(VB_GENERAL, LOG_DEBUG, " DTS");
307  printpts(viu->dts);
308  printpts(mx->video_delay);
309 #endif
310 
311  if (viu->length == 0){
312  get_next_video_unit(mx, viu);
313  }
314 
315 }
316 
317 static void writeout_ext(multiplex_t *mx, int n)
318 {
319  uint8_t outbuf[3000];
320  int written=0;
321  uint64_t dpts=0;
322  int newpts=0;
323  int nframes=1;
324  int ac3_off=0;
325  int rest_data = 5;
326 
327  int type = mx->ext[n].type;
328  ringbuffer *airbuffer = &mx->index_extrbuffer[n];
329  dummy_buffer *dbuf = &mx->ext[n].dbuf;
330  uint64_t adelay = mx->ext[n].pts_off;
331  uint64_t *apts = &mx->ext[n].pts;
332  index_unit *aiu = &mx->ext[n].iu;
333 
334  switch (type){
335 
336  case MPEG_AUDIO:
337 #ifdef OUT_DEBUG
338  LOG(VB_GENERAL, LOG_DEBUG, "writing AUDIO%d pack\n", n);
339 #endif
340  break;
341 
342  case AC3:
343 #ifdef OUT_DEBUG
344  LOG(VB_GENERAL, LOG_DEBUG, "writing AC3%d pack\n", n);
345 #endif
346  rest_data = 1; // 4 bytes AC3 header
347  break;
348 
349  default:
350  return;
351  }
352 
353  if (mx->finish != 2 && dummy_space(dbuf) < mx->data_size + rest_data){
354  return;
355  }
356 
357  uint64_t pts = uptsdiff( aiu->pts + mx->audio_delay, adelay );
358  *apts = pts;
359  unsigned int length = aiu->length;
360  if (length < aiu->framesize){
361  newpts = 1;
362  ac3_off = length;
363  }
364  dummy_add(dbuf, pts, aiu->length);
365 
366 #ifdef OUT_DEBUG
367  LOG(VB_GENERAL, LOG_DEBUG, "start: %d stop: %d (%d) length %d",
368  aiu->start, (aiu->start+aiu->length),
369  aiu->length, length);
370  printpts(*apts);
371  printpts(aiu->pts);
372  printpts(mx->audio_delay);
373  printpts(adelay);
374  printpts(pts);
375 #endif
376  while (!mx->is_ts && length < mx->data_size + rest_data){
377  if (ring_read(airbuffer, (uint8_t *)aiu, sizeof(index_unit)) > 0){
378  dpts = uptsdiff(aiu->pts +mx->audio_delay, adelay );
379 
380  if (newpts){
381  pts = dpts;
382  newpts=0;
383  }
384 
385  length+= aiu->length;
386  if (length < mx->data_size + rest_data)
387  dummy_add(dbuf, dpts, aiu->length);
388 
389  *apts = dpts;
390  nframes++;
391 #ifdef OUT_DEBUG
392  LOG(VB_GENERAL, LOG_DEBUG,
393  "start: %d stop: %d (%d) length %d",
394  aiu->start, (aiu->start+aiu->length),
395  aiu->length, length);
396  printpts(*apts);
397  printpts(aiu->pts);
398  printpts(mx->audio_delay);
399  printpts(adelay);
400 #endif
401  } else if (mx->finish){
402  break;
403  } else if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
404  LOG(VB_GENERAL, LOG_ERR, "error in writeout ext");
405  exit(1);
406  }
407  }
408 
409  int nlength = length;
410 
411  switch (type) {
412  case MPEG_AUDIO:
413  if(mx->is_ts) {
414  written = write_audio_ts( mx->ext[n].strmnum, pts,
415  outbuf, &nlength, newpts ? 0 : PTS_ONLY,
416  &mx->extrbuffer[n]);
417  } else {
418  written = write_audio_pes( mx->pack_size, mx->extcnt,
419  mx->ext[n].strmnum, pts, mx->SCR,
420  mx->muxr, outbuf, &nlength, PTS_ONLY,
421  &mx->extrbuffer[n]);
422  }
423  break;
424  case AC3:
425  if(mx->is_ts) {
426  written = write_ac3_ts(mx->ext[n].strmnum, pts,
427  outbuf, &nlength, newpts ? 0 : PTS_ONLY,
428  mx->ext[n].frmperpkt, &mx->extrbuffer[n]);
429  } else {
430  written = write_ac3_pes( mx->pack_size, mx->extcnt,
431  mx->ext[n].strmnum, pts, mx->SCR,
432  mx->muxr, outbuf, &nlength, PTS_ONLY,
433  nframes, ac3_off,
434  &mx->extrbuffer[n]);
435  }
436  break;
437  }
438 
439  // something bad happened when writing TS or PES to the MPEG or AC3
440  // audio stream
441  if (written == -1)
442  return;
443 
444  length -= nlength;
445  write(mx->fd_out, outbuf, written);
446 
447  dummy_add(dbuf, dpts, aiu->length-length);
448  aiu->length = length;
449  aiu->start = ring_rpos(&mx->extrbuffer[n]);
450 
451  if (aiu->length == 0){
452  get_next_ext_unit(mx, aiu, n);
453  } else {
454  //estimate next pts based on bitrate of stream and data written
455  aiu->pts = uptsdiff(aiu->pts + ((nlength*aiu->ptsrate)>>8), 0);
456  }
457  *apts = uptsdiff(aiu->pts + mx->audio_delay, adelay);
458 #ifdef OUT_DEBUG
459  if ((int64_t)*apts < 0)
460  LOG(VB_GENERAL, LOG_DEBUG, "SCHEISS APTS");
461  printpts(*apts);
462  printpts(aiu->pts);
463  printpts(mx->audio_delay);
464  printpts(adelay);
465 #endif
466 
467  if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
468  LOG(VB_GENERAL, LOG_ERR, "error in writeout ext");
469  exit(1);
470  }
471 }
472 
473 static void writeout_padding (multiplex_t *mx)
474 {
475  uint8_t outbuf[3000];
476 #if 0
477  LOG(VB_GENERAL, LOG_INFO, "writing PADDING pack");
478 #endif
479 
480  write_padding_pes( mx->pack_size, mx->extcnt, mx->SCR,
481  mx->muxr, outbuf);
482  write(mx->fd_out, outbuf, mx->pack_size);
483 }
484 
485 void check_times( multiplex_t *mx, int *video_ok, int *ext_ok, int *start)
486 {
487  int set_ok = 0;
488 
489  memset(ext_ok, 0, N_AUDIO*sizeof(int));
490  *video_ok = 0;
491 
492  if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
493  LOG(VB_GENERAL, LOG_ERR, "error in get next video unit");
494  return;
495  }
496 
497  /* increase SCR to next packet */
498  mx->oldSCR = mx->SCR;
499  if (!*start){
500  ptsinc(&mx->SCR, mx->SCRinc);
501  } else *start = 0;
502 
503  if (mx->VBR) {
504 #ifdef OUT_DEBUG1
505  LOG(VB_GENERAL, LOG_DEBUG, "EXTRACLOCK: %lli", mx->extra_clock);
506  printpts(mx->extra_clock);
507 #endif
508 
509  if (mx->extra_clock > 0.0) {
510  int64_t d = mx->extra_clock/ mx->SCRinc - 1;
511  if (d > 0)
512  mx->extra_clock = d*mx->SCRinc;
513  else
514  mx->extra_clock = 0.0;
515  }
516 
517  if (mx->extra_clock > 0.0) {
518  int64_t temp_scr = mx->extra_clock;
519 
520  for (int i=0; i<mx->extcnt; i++){
521  if (ptscmp(mx->SCR + temp_scr + 100*CLOCK_MS,
522  mx->ext[i].iu.pts) > 0) {
523  while (ptscmp(mx->SCR + temp_scr
524  + 100*CLOCK_MS,
525  mx->ext[i].iu.pts) > 0)
526  temp_scr -= mx->SCRinc;
527  temp_scr += mx->SCRinc;
528  }
529  }
530 
531  if (temp_scr > 0.0) {
532  mx->SCR += temp_scr;
533  mx->extra_clock -= temp_scr;
534  } else
535  mx->extra_clock = 0.0;
536  }
537  }
538 
539  /* clear decoder buffers up to SCR */
540  dummy_delete(&mx->vdbuf, mx->SCR);
541 
542  for (int i=0;i <mx->extcnt; i++)
543  dummy_delete(&mx->ext[i].dbuf, mx->SCR);
544 
545  if (dummy_space(&mx->vdbuf) > mx->vsize && mx->viu.length > 0 &&
546  (ptscmp(mx->viu.dts + mx->video_delay, 500*CLOCK_MS +mx->oldSCR)<0)
547  && ring_avail(mx->index_vrbuffer)){
548  *video_ok = 1;
549  set_ok = 1; //NOLINT(clang-analyzer-deadcode.DeadStores)
550  }
551 
552  for (int i = 0; i < mx->extcnt; i++){
553  if (dummy_space(&mx->ext[i].dbuf) > mx->extsize &&
554  mx->ext[i].iu.length > 0 &&
555  ptscmp(mx->ext[i].pts, 500*CLOCK_MS + mx->oldSCR) < 0
556  && ring_avail(&mx->index_extrbuffer[i])){
557  ext_ok[i] = 1;
558  set_ok = 1; //NOLINT(clang-analyzer-deadcode.DeadStores)
559  }
560  }
561 #ifdef OUT_DEBUG
562  if (set_ok) {
563  LOG(VB_GENERAL, LOG_DEBUG, "SCR");
564  printpts(mx->oldSCR);
565  LOG(VB_GENERAL, LOG_DEBUG, "VDTS");
566  printpts(mx->viu.dts);
567  LOG(VB_GENERAL, LOG_DEBUG, " (%d) EXT", *video_ok);
568  for (i = 0; i < mx->extcnt; i++){
569  LOG(VB_GENERAL, LOG_DEBUG, "%d:", mx->ext[i].type);
570  printpts(mx->ext[i].pts);
571  LOG(VB_GENERAL, LOG_DEBUG, " (%d)", ext_ok[i]);
572  }
573  }
574 #endif
575 }
576 void write_out_packs( multiplex_t *mx, int video_ok, int *ext_ok)
577 {
578  if (video_ok && use_video(mx->viu.dts + mx->video_delay,
579  mx->ext, ext_ok, mx->extcnt)) {
580  writeout_video(mx);
581  } else { // second case(s): audio ok, video in time
582  int i = which_ext(mx->ext, ext_ok, mx->extcnt);
583  int done=0;
584  if(i>=0) {
585  writeout_ext(mx, i);
586  done = 1;
587  }
588  if (!done && !mx->VBR){
589  writeout_padding(mx);
590  }
591  }
592 
593 }
594 
596 {
597  int start=0;
598  int video_ok = 0;
599  int ext_ok[N_AUDIO];
600  int n = 0;
601  uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 };
602 
603  memset(ext_ok, 0, N_AUDIO*sizeof(int));
604  mx->finish = 1;
605 
606  int old = 0;
607  int nn=0;
608  while ((n=buffers_filled(mx)) && nn<1000 ){
609  if (n== old) nn++;
610  else nn=0;
611  old = n;
612  check_times( mx, &video_ok, ext_ok, &start);
613  write_out_packs( mx, video_ok, ext_ok);
614  }
615 
616  old = 0;nn=0;
617  while ((n=ring_avail(mx->index_vrbuffer)/sizeof(index_unit))
618  && nn<1000){
619  if (n== old) nn++;
620  else nn= 0;
621  old = n;
622  writeout_video(mx);
623  }
624 
625 // flush the rest
626  mx->finish = 2;
627  old = 0;nn=0;
628  for (int i = 0; i < mx->extcnt; i++){
629  while ((n=ring_avail(&mx->index_extrbuffer[i])/
630  sizeof(index_unit)) && nn <100){
631  if (n== old) nn++;
632  else nn = 0;
633  old = n;
634  writeout_ext(mx, i);
635  }
636  }
637 
638  if (mx->otype == REPLEX_MPEG2)
639  write(mx->fd_out, mpeg_end,4);
640 
641  dummy_destroy(&mx->vdbuf);
642  for (int i=0; i<mx->extcnt;i++)
643  dummy_destroy(&mx->ext[i].dbuf);
644 }
645 
646 static int get_ts_video_overhead(int pktsize, sequence_t *seq)
647 {
648  int pktdata = pktsize - TS_HEADER_MIN;
649  uint32_t framesize = seq->bit_rate * 50 / seq->frame_rate; //avg bytes/frame
650  uint32_t numpkt = (framesize + PES_H_MIN + 10 + pktdata -1) / pktdata;
651  return pktsize- ((pktsize * numpkt) - framesize + numpkt - 1) / numpkt;
652 }
653 
654 static int get_ts_ext_overhead(int pktsize, audio_frame_t *extframe,
655  extdata_t *ext, int cnt)
656 {
657  int max = 0;
658  int pktdata = pktsize - TS_HEADER_MIN;
659  for (int i = 0; i < cnt; i++) {
660  // 1/53 is approx 0.15 * 1/8 which allows us to calculate the
661  // # of packets in .15 seconds (which is the number of packets
662  // per PES.
663  ext[i].frmperpkt = extframe[i].bit_rate / 53 /
664  extframe[i].framesize;
665  int size = extframe[i].framesize * ext[i].frmperpkt;
666  int numpkt = (size + pktdata - 1) / pktdata;
667  int overhead = (pktsize * numpkt - size + numpkt - 1) / numpkt;
668  if(overhead > max)
669  max = overhead;
670  }
671  return pktsize - max;
672 }
673 
674 void init_multiplex( multiplex_t *mx, sequence_t *seq_head,
675  audio_frame_t *extframe, int *exttype, const int *exttypcnt,
676  uint64_t video_delay, uint64_t audio_delay, int fd,
677  int (*fill_buffers)(void *p, int f),
678  ringbuffer *vrbuffer, ringbuffer *index_vrbuffer,
679  ringbuffer *extrbuffer, ringbuffer *index_extrbuffer,
680  int otype)
681 {
682  int i = 0;
683  uint32_t data_rate = 0;
684 
686  mx->video_delay = video_delay;
687  mx->audio_delay = audio_delay;
688  mx->fd_out = fd;
689  mx->otype = otype;
690 
691  switch(mx->otype){
692 
693  case REPLEX_DVD:
694  mx->video_delay += 180*CLOCK_MS;
695  mx->audio_delay += 180*CLOCK_MS;
696  mx->pack_size = 2048;
697  mx->audio_buffer_size = 4*1024;
698  mx->video_buffer_size = 232*1024;
699  mx->mux_rate = 1260000;
700  mx->navpack = 1;
702  mx->VBR = 1;
703  mx->reset_clocks = 0;
704  mx->write_end_codes = 0;
705  mx->set_broken_link = 0;
706  mx->is_ts = 0;
707  break;
708 
709 
710  case REPLEX_MPEG2:
711  mx->video_delay += 180*CLOCK_MS;
712  mx->audio_delay += 180*CLOCK_MS;
713  mx->pack_size = 2048;
714  mx->audio_buffer_size = 4*1024;
715  mx->video_buffer_size = 224*1024;
716  mx->mux_rate = 0;
717  mx->navpack = 0;
719  mx->VBR = 1;
720  mx->reset_clocks = 1;
721  mx->write_end_codes = 1;
722  mx->set_broken_link = 1;
723  mx->is_ts = 0;
724  break;
725 
726  case REPLEX_HDTV:
727  mx->video_delay += 180*CLOCK_MS;
728  mx->audio_delay += 180*CLOCK_MS;
729  mx->pack_size = 2048;
730  mx->audio_buffer_size = 4*1024;
731  mx->video_buffer_size = 4*224*1024;
732  mx->mux_rate = 0;
733  mx->navpack = 0;
735  mx->VBR = 1;
736  mx->reset_clocks = 1;
737  mx->write_end_codes = 1;
738  mx->set_broken_link = 1;
739  mx->is_ts = 0;
740  break;
741 
742  case REPLEX_TS_SD:
743  mx->video_delay += 180*CLOCK_MS;
744  mx->audio_delay += 180*CLOCK_MS;
745  mx->pack_size = 188;
746  mx->audio_buffer_size = 4*1024;
747  mx->video_buffer_size = 232*1024;
748  mx->mux_rate = 1260000;
749  mx->navpack = 0;
751  mx->VBR = 1;
752  mx->reset_clocks = 0;
753  mx->write_end_codes = 0;
754  mx->set_broken_link = 0;
755  mx->is_ts = 1;
756  break;
757 
758  case REPLEX_TS_HD:
759  mx->video_delay += 180*CLOCK_MS;
760  mx->audio_delay += 180*CLOCK_MS;
761  mx->pack_size = 188;
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 = 0;
769  mx->write_end_codes = 0;
770  mx->set_broken_link = 0;
771  mx->is_ts = 1;
772  break;
773  }
774 
775  for (mx->extcnt = 0, data_rate = 0, i = 0;
776  i < N_AUDIO && exttype[i]; i++){
777  if (exttype[i] >= MAX_TYPES) {
778  LOG(VB_GENERAL, LOG_ERR, "Found illegal stream type %d",
779  exttype[i]);
780  exit(1);
781  }
782  mx->ext[i].type = exttype[i];
783  mx->ext[i].pts_off = 0;
784  mx->ext[i].frmperpkt = 1;
785  mx->ext[i].strmnum = exttypcnt[i];
786  strncpy(mx->ext[i].language, extframe[i].language, 4);
787  dummy_init(&mx->ext[i].dbuf, mx->audio_buffer_size);
788  data_rate += extframe[i].bit_rate;
789  mx->extcnt++;
790  }
791 
792  mx->vrbuffer = vrbuffer;
793  mx->index_vrbuffer = index_vrbuffer;
794  mx->extrbuffer = extrbuffer;
795  mx->index_extrbuffer = index_extrbuffer;
796 
798 
799  //NOTE: vpkt_hdr/extpkt_hdr are worst-case for PS streams, but
800  //best-guess for TS streams
801  if(mx->is_ts) {
802  //Use best guess for TS streams
803  mx->data_size = get_ts_video_overhead(mx->pack_size, seq_head);
804  mx->extsize = get_ts_ext_overhead(mx->pack_size, extframe,
805  mx->ext, mx->extcnt);
806 
807  } else {
808  //Use worst case for PS streams
809  mx->data_size = mx->pack_size - PES_H_MIN - PS_HEADER_L1 - 10;
810  mx->extsize = mx->data_size + 5; //one less DTS
811  }
812  mx->vsize = mx->data_size;
813 
814  data_rate += seq_head->bit_rate *400;
815 
816  mx->muxr = ((uint64_t)data_rate / 8 * mx->pack_size) / mx->data_size;
817  // muxrate of payload in Byte/s
818 
819  if (mx->mux_rate) {
820  if ( mx->mux_rate < mx->muxr)
821  LOG(VB_GENERAL, LOG_WARNING,
822  "data rate may be to high for required mux rate");
823  mx->muxr = mx->mux_rate;
824  }
825  LOG(VB_GENERAL, LOG_INFO, "Mux rate: %.2f Mbit/s",
826  mx->muxr*8.0/1000000.0);
827 
828  mx->SCRinc = 27000000ULL/((uint64_t)mx->muxr /
829  (uint64_t) mx->pack_size);
830 
831 }
832 
834 {
835  get_next_video_unit(mx, &mx->viu);
836  for (int i=0; i < mx->extcnt; i++)
837  {
838  get_next_ext_unit(mx, &mx->ext[i].iu, i);
839  if (mx->ext[i].type == MPEG_AUDIO || mx->ext[i].type == AC3) {
840  mx->ext[i].pts = uptsdiff(
841  mx->ext[i].iu.pts + mx->audio_delay,
842  mx->ext[i].pts_off);
843  } else {
844  mx->ext[i].pts = uptsdiff(
845  mx->ext[i].iu.pts, mx->ext[i].pts_off);
846  }
847  }
848 
849  mx->SCR = 0;
850 
851  // write first VOBU header
852  if (mx->is_ts) {
853  uint8_t outbuf[2048];
854  write_ts_patpmt(mx->ext, mx->extcnt, 1, outbuf);
855  write(mx->fd_out, outbuf, mx->pack_size*2);
856  ptsinc(&mx->SCR, mx->SCRinc*2);
857  mx->startup = 1;
858  } else if (mx->navpack){
859  uint8_t outbuf[2048];
860  write_nav_pack(mx->pack_size, mx->extcnt,
861  mx->SCR, mx->muxr, outbuf);
862  write(mx->fd_out, outbuf, mx->pack_size);
863  ptsinc(&mx->SCR, mx->SCRinc);
864  mx->startup = 1;
865  } else mx->startup = 0;
866 }
#define CLOCK_MS
Definition: element.h:77
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.c:685
int frame_timestamps
Definition: multiplex.h:59
def write(text, progress=True)
Definition: mythburn.py:279
uint64_t pts_off
Definition: mpg_common.h:57
uint32_t length
Definition: mpg_common.h:37
ringbuffer * extrbuffer
Definition: multiplex.h:77
uint64_t dts
Definition: mpg_common.h:40
int write_end_codes
Definition: multiplex.h:63
int64_t ptsdiff(uint64_t pts1, uint64_t pts2)
Definition: pes.c:78
static int ring_rpos(ringbuffer *rbuf)
#define PS_HEADER_L1
Definition: pes.h:13
uint32_t bit_rate
Definition: element.h:112
int write_audio_ts(int n, uint64_t pts, uint8_t *buf, int *alength, uint8_t ptsdts, ringbuffer *arbuffer)
Definition: ts.c:285
unsigned int extsize
Definition: multiplex.h:65
Definition: element.h:83
uint32_t muxr
Definition: multiplex.h:55
uint64_t ptsrate
Definition: mpg_common.h:51
index_unit viu
Definition: multiplex.h:70
#define REPLEX_TS_HD
Definition: multiplex.h:42
uint32_t framesize
Definition: element.h:117
static int peek_next_ext_unit(multiplex_t *mx, index_unit *extiu, int i)
Definition: multiplex.c:100
uint64_t audio_delay
Definition: multiplex.h:49
int type
Definition: mpg_common.h:58
uint32_t video_buffer_size
Definition: multiplex.h:53
static int fill_buffers(void *r, int finish)
Definition: replex.c:1821
#define TIME_IFRAME
Definition: multiplex.h:58
uint64_t pts
Definition: mpg_common.h:39
uint32_t audio_buffer_size
Definition: multiplex.h:52
static void writeout_ext(multiplex_t *mx, int n)
Definition: multiplex.c:317
uint32_t start
Definition: mpg_common.h:38
uint64_t SCRinc
Definition: multiplex.h:69
int write_ac3_ts(int n, uint64_t pts, uint8_t *buf, int *alength, uint8_t ptsdts, int nframes, ringbuffer *ac3rbuffer)
Definition: ts.c:328
static int use_video(uint64_t vpts, extdata_t *ext, const int *aok, int n)
Definition: multiplex.c:23
static void writeout_video(multiplex_t *mx)
Definition: multiplex.c:184
int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
Definition: ringbuffer.c:412
#define REPLEX_HDTV
Definition: multiplex.h:40
static void writeout_padding(multiplex_t *mx)
Definition: multiplex.c:473
int pack_size
Definition: multiplex.h:50
#define TIME_ALWAYS
Definition: multiplex.h:57
unsigned int data_size
Definition: multiplex.h:51
void finish_mpg(multiplex_t *mx)
Definition: multiplex.c:595
struct index_unit_s index_unit
#define I_FRAME
Definition: element.h:53
#define PTS_ONLY
Definition: pes.h:46
int startup
Definition: multiplex.h:44
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.c:232
int extcnt
Definition: multiplex.h:75
void printpts(int64_t pts)
Definition: pes.c:42
int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.c:179
uint8_t seq_header
Definition: mpg_common.h:41
static int which_ext(extdata_t *ext, const int *aok, int n)
Definition: multiplex.c:30
int ptscmp(uint64_t pts1, uint64_t pts2)
Definition: pes.c:114
#define P_FRAME
Definition: element.h:54
uint64_t SCR
Definition: multiplex.h:67
uint64_t pts
Definition: mpg_common.h:56
void write_ts_patpmt(extdata_t *ext, int extcnt, uint8_t prog_num, uint8_t *buf)
Definition: ts.c:378
static int get_ts_ext_overhead(int pktsize, audio_frame_t *extframe, extdata_t *ext, int cnt)
Definition: multiplex.c:654
static int get_next_ext_unit(multiplex_t *mx, index_unit *extiu, int i)
Definition: multiplex.c:124
static uint8_t get_ptsdts(multiplex_t *mx, index_unit *viu)
Definition: multiplex.c:165
uint8_t frame_start
Definition: mpg_common.h:48
uint8_t frame
Definition: mpg_common.h:45
void * priv
Definition: multiplex.h:83
void dummy_destroy(dummy_buffer *dbuf)
Definition: ringbuffer.c:399
uint32_t mux_rate
Definition: multiplex.h:54
static const uint16_t * d
void exit(int retcode=0)
Use this to exit from the thread if you are using a Qt event loop.
Definition: mthread.cpp:289
void write_out_packs(multiplex_t *mx, int video_ok, int *ext_ok)
Definition: multiplex.c:576
static unsigned int ring_avail(ringbuffer *rbuf)
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.c:780
void pts2time(uint64_t pts, uint8_t *buf, int len)
Definition: element.c:151
void setup_multiplex(multiplex_t *mx)
Definition: multiplex.c:833
int finish
Definition: multiplex.h:45
uint64_t uptsdiff(uint64_t pts1, uint64_t pts2)
Definition: pes.c:104
int write_nav_pack(int pack_size, int extcnt, uint64_t SCR, uint32_t muxr, uint8_t *buf)
Definition: pes.c:833
uint8_t gop
Definition: mpg_common.h:43
#define PES_H_MIN
Definition: pes.h:16
#define REPLEX_DVD
Definition: multiplex.h:39
int ring_peek(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.c:121
char language[4]
Definition: mpg_common.h:61
int frmperpkt
Definition: mpg_common.h:60
int strmnum
Definition: mpg_common.h:59
uint32_t frame_rate
Definition: element.h:92
ringbuffer * index_vrbuffer
Definition: multiplex.h:80
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
unsigned int vsize
Definition: multiplex.h:65
#define REPLEX_MPEG2
Definition: multiplex.h:38
uint64_t video_delay
Definition: multiplex.h:48
index_unit iu
Definition: mpg_common.h:55
extdata_t ext[N_AUDIO]
Definition: multiplex.h:74
int dummy_init(dummy_buffer *dbuf, int s)
Definition: ringbuffer.c:387
int(* fill_buffers)(void *p, int f)
Definition: multiplex.h:82
int64_t extra_clock
Definition: multiplex.h:66
static uint32_t dummy_space(dummy_buffer *dbuf)
int dummy_delete(dummy_buffer *dbuf, uint64_t time)
Definition: ringbuffer.c:429
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.c:735
void check_times(multiplex_t *mx, int *video_ok, int *ext_ok, int *start)
Definition: multiplex.c:485
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
uint8_t navpack
Definition: multiplex.h:56
int set_broken_link
Definition: multiplex.h:64
dummy_buffer vdbuf
Definition: multiplex.h:72
int reset_clocks
Definition: multiplex.h:62
uint32_t framesize
Definition: mpg_common.h:50
#define N_AUDIO
Definition: multiplex.h:33
void write_padding_pes(int pack_size, int extcnt, uint64_t SCR, uint64_t muxr, uint8_t *buf)
Definition: pes.c:673
#define TS_HEADER_MIN
Definition: pes.h:12
static int buffers_filled(multiplex_t *mx)
Definition: multiplex.c:9
#define PTS_DTS
Definition: pes.h:47
char language[4]
Definition: element.h:120
int ring_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.c:150
ringbuffer * vrbuffer
Definition: multiplex.h:79
void init_multiplex(multiplex_t *mx, sequence_t *seq_head, audio_frame_t *extframe, int *exttype, const int *exttypcnt, uint64_t video_delay, uint64_t audio_delay, int fd, int(*fill_buffers)(void *p, int f), ringbuffer *vrbuffer, ringbuffer *index_vrbuffer, ringbuffer *extrbuffer, ringbuffer *index_extrbuffer, int otype)
Definition: multiplex.c:674
int fd_out
Definition: multiplex.h:37
uint64_t oldSCR
Definition: multiplex.h:68
#define REPLEX_TS_SD
Definition: multiplex.h:41
static int peek_next_video_unit(multiplex_t *mx, index_unit *viu)
Definition: multiplex.c:50
static int get_ts_video_overhead(int pktsize, sequence_t *seq)
Definition: multiplex.c:646
static void ptsinc(uint64_t *pts1, uint64_t pts2)
Definition: pes.h:129
static int get_next_video_unit(multiplex_t *mx, index_unit *viu)
Definition: multiplex.c:73
uint32_t bit_rate
Definition: element.h:93
dummy_buffer dbuf
Definition: mpg_common.h:62
ringbuffer * index_extrbuffer
Definition: multiplex.h:78