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