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