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