00001 #include <unistd.h>
00002 #include <string.h>
00003 #include <stdlib.h>
00004
00005 #include "multiplex.h"
00006 #include "ts.h"
00007 #include "mythlogging.h"
00008
00009 static int buffers_filled(multiplex_t *mx)
00010 {
00011 int vavail=0, aavail=0, i;
00012
00013 vavail = ring_avail(mx->index_vrbuffer)/sizeof(index_unit);
00014
00015 for (i=0; i<mx->extcnt;i++){
00016 aavail += ring_avail(&mx->index_extrbuffer[i])/
00017 sizeof(index_unit);
00018 }
00019
00020 if (aavail+vavail) return ((aavail+vavail));
00021 return 0;
00022 }
00023
00024 static int use_video(uint64_t vpts, extdata_t *ext, int *aok, int n)
00025 {
00026 int i;
00027 for(i=0; i < n; i++)
00028 if(aok[i] && ptscmp(vpts,ext[i].pts) > 0)
00029 return 0;
00030 return 1;
00031 }
00032 static int which_ext(extdata_t *ext, int *aok, int n)
00033 {
00034 int i;
00035 int started = 0;
00036 int pos = -1;
00037 uint64_t tmppts = 0;
00038 for(i=0; i < n; i++)
00039 if(aok[i]){
00040 if(! started){
00041 started=1;
00042 tmppts=ext[i].pts;
00043 pos = i;
00044 } else if(ptscmp(tmppts, ext[i].pts) > 0) {
00045 tmppts = ext[i].pts;
00046 pos = i;
00047 }
00048 }
00049 return pos;
00050 }
00051
00052 static int peek_next_video_unit(multiplex_t *mx, index_unit *viu)
00053 {
00054 if (!ring_avail(mx->index_vrbuffer) && mx->finish) return 0;
00055
00056 while (ring_avail(mx->index_vrbuffer) < sizeof(index_unit))
00057 if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
00058 LOG(VB_GENERAL, LOG_ERR,
00059 "error in peek next video unit");
00060 return 0;
00061 }
00062
00063 ring_peek(mx->index_vrbuffer, (uint8_t *)viu, sizeof(index_unit),0);
00064 #ifdef OUT_DEBUG
00065 LOG(VB_GENERAL, LOG_DEBUG,
00066 "video index start: %d stop: %d (%d) rpos: %d\n",
00067 viu->start, (viu->start+viu->length),
00068 viu->length, ring_rpos(mx->vrbuffer));
00069 #endif
00070
00071 return 1;
00072 }
00073
00074 static int get_next_video_unit(multiplex_t *mx, index_unit *viu)
00075 {
00076 index_unit nviu;
00077 if (!ring_avail(mx->index_vrbuffer) && mx->finish) return 0;
00078
00079 while (ring_avail(mx->index_vrbuffer) < sizeof(index_unit))
00080 if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
00081 LOG(VB_GENERAL, LOG_ERR,
00082 "error in get next video unit");
00083 return 0;
00084 }
00085
00086 ring_read(mx->index_vrbuffer, (uint8_t *)viu, sizeof(index_unit));
00087 #ifdef OUT_DEBUG
00088 LOG(VB_GENERAL, LOG_INFO,
00089 "video index start: %d stop: %d (%d) rpos: %d\n",
00090 viu->start, (viu->start+viu->length),
00091 viu->length, ring_rpos(mx->vrbuffer));
00092 #endif
00093 if(! peek_next_video_unit(mx, &nviu))
00094 return 1;
00095
00096 viu->ptsrate = (uptsdiff(nviu.dts, viu->dts) << 8) / viu->length;
00097 return 1;
00098 }
00099
00100 static int peek_next_ext_unit(multiplex_t *mx, index_unit *extiu, int i)
00101 {
00102 if (!ring_avail(&mx->index_extrbuffer[i]) && mx->finish) return 0;
00103
00104 while (ring_avail(&mx->index_extrbuffer[i]) < sizeof(index_unit))
00105 if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
00106 LOG(VB_GENERAL, LOG_ERR,
00107 "error in peek next video unit");
00108 return 0;
00109 }
00110
00111 ring_peek(&mx->index_extrbuffer[i], (uint8_t *)extiu,
00112 sizeof(index_unit),0);
00113 #ifdef OUT_DEBUG
00114 LOG(VB_GENERAL, LOG_DEBUG,
00115 "ext index start: %d stop: %d (%d) rpos: %d",
00116 extiu->start, (extiu->start+extiu->length),
00117 extiu->length, ring_rpos(mx->extrbuffer));
00118 #endif
00119
00120 return 1;
00121 }
00122
00123 static int get_next_ext_unit(multiplex_t *mx, index_unit *extiu, int i)
00124 {
00125 index_unit niu, *piu = extiu;
00126 int j, length = 0;
00127 for(j = 0; j < mx->ext[i].frmperpkt; j++) {
00128 if (!ring_avail(&mx->index_extrbuffer[i]) && mx->finish)
00129 break;
00130
00131 while(ring_avail(&mx->index_extrbuffer[i]) < sizeof(index_unit))
00132 if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
00133 LOG(VB_GENERAL, LOG_ERR,
00134 "error in get next ext unit");
00135 break;
00136 }
00137
00138 ring_read(&mx->index_extrbuffer[i], (uint8_t *)piu,
00139 sizeof(index_unit));
00140 length += piu->length;
00141 piu = &niu;
00142 }
00143 if (j == 0)
00144 return 0;
00145 extiu->length = length;
00146 extiu->framesize = length;
00147 if(! peek_next_ext_unit(mx, &niu, i))
00148 return 1;
00149
00150 extiu->ptsrate = (uptsdiff(niu.pts, extiu->pts) << 8) / extiu->length;
00151
00152 #ifdef OUT_DEBUG
00153 LOG(VB_GENERAL, LOG_DEBUG,
00154 "ext index start: %d stop: %d (%d) rpos: %d",
00155 extiu->start, (extiu->start+extiu->length),
00156 extiu->length, ring_rpos(&mx->extrbuffer[i]));
00157 #endif
00158 return 1;
00159 }
00160
00161 static uint8_t get_ptsdts(multiplex_t *mx, index_unit *viu)
00162 {
00163 uint8_t ptsdts = 0;
00164 switch (mx->frame_timestamps){
00165 case TIME_ALWAYS:
00166 if (viu->frame == I_FRAME || viu->frame == P_FRAME)
00167 ptsdts = PTS_DTS;
00168 else
00169 ptsdts = PTS_ONLY;
00170 break;
00171
00172 case TIME_IFRAME:
00173 if (viu->frame == I_FRAME)
00174 ptsdts = PTS_DTS;
00175 break;
00176 }
00177 return ptsdts;
00178 }
00179
00180 static void writeout_video(multiplex_t *mx)
00181 {
00182 uint8_t outbuf[3000];
00183 int written=0;
00184 uint8_t ptsdts=0;
00185 unsigned int length;
00186 int nlength=0;
00187 int frame_len=0;
00188 index_unit *viu = &mx->viu;
00189
00190 #ifdef OUT_DEBUG
00191 LOG(VB_GENERAL, LOG_DEBUG, "writing VIDEO pack");
00192 #endif
00193
00194 if(viu->frame_start) {
00195 ptsdts = get_ptsdts(mx, viu);
00196 frame_len = viu->length;
00197 }
00198
00199 if (viu->frame_start && viu->seq_header && viu->gop &&
00200 viu->frame == I_FRAME){
00201 if (!mx->startup && mx->is_ts){
00202 write_ts_patpmt(mx->ext, mx->extcnt, 1, outbuf);
00203 write(mx->fd_out, outbuf, mx->pack_size*2);
00204 ptsinc(&mx->SCR, mx->SCRinc*2);
00205 } else if (!mx->startup && mx->navpack){
00206 write_nav_pack(mx->pack_size, mx->extcnt,
00207 mx->SCR, mx->muxr, outbuf);
00208 write(mx->fd_out, outbuf, mx->pack_size);
00209 ptsinc(&mx->SCR, mx->SCRinc);
00210 } else mx->startup = 0;
00211 #ifdef OUT_DEBUG
00212 LOG(VB_GENERAL, LOG_DEBUG, " with sequence and gop header");
00213 #endif
00214 }
00215
00216 if (mx->finish != 2 && dummy_space(&mx->vdbuf) < mx->data_size){
00217 return;
00218 }
00219 length = viu->length;
00220 while (!mx->is_ts && length < mx->data_size){
00221 index_unit nviu;
00222 int old_start = viu->frame_start;
00223 int old_frame = viu->frame;
00224 uint64_t old_pts = viu->pts;
00225 uint64_t old_dts = viu->dts;
00226 dummy_add(&mx->vdbuf, uptsdiff(viu->dts+mx->video_delay,0)
00227 , viu->length);
00228 if ( peek_next_video_unit(mx, &nviu)){
00229 if (!(nviu.seq_header && nviu.gop &&
00230 nviu.frame == I_FRAME)){
00231 get_next_video_unit(mx, viu);
00232 frame_len = viu->length;
00233 length += viu->length;
00234 if(old_start) {
00235 viu->pts = old_pts;
00236 viu->dts = old_dts;
00237 viu->frame = old_frame;
00238 } else {
00239 ptsdts = get_ptsdts(mx, viu);
00240 }
00241 } else break;
00242 } else break;
00243 }
00244
00245 if (viu->frame_start){
00246 viu->frame_start=0;
00247 if (viu->gop){
00248 uint8_t gop[8];
00249 frame_len=length-frame_len;
00250 ring_peek(mx->vrbuffer, gop, 8, frame_len);
00251 pts2time( viu->pts + mx->video_delay, gop, 8);
00252 ring_poke(mx->vrbuffer, gop, 8, frame_len);
00253 viu->gop=0;
00254 }
00255 if (mx->VBR) {
00256 mx->extra_clock = ptsdiff(viu->dts + mx->video_delay,
00257 mx->SCR + 500*CLOCK_MS);
00258 #ifdef OUT_DEBUG1
00259 LOG(VB_GENERAL, LOG_DEBUG,
00260 "EXTRACLOCK2: %lli %lli %lli",
00261 viu->dts, mx->video_delay, mx->SCR);
00262 LOG(VB_GENERAL, LOG_DEBUG, "EXTRACLOCK2: %lli",
00263 mx->extra_clock);
00264 printpts(mx->extra_clock);
00265 #endif
00266
00267 if (mx->extra_clock < 0)
00268 mx->extra_clock = 0.0;
00269 }
00270 }
00271
00272
00273 nlength = length;
00274 if (mx->is_ts)
00275 written = write_video_ts( viu->pts+mx->video_delay,
00276 viu->dts+mx->video_delay,
00277 mx->SCR, outbuf, &nlength,
00278 ptsdts, mx->vrbuffer);
00279 else
00280 written = write_video_pes( mx->pack_size, mx->extcnt,
00281 viu->pts+mx->video_delay,
00282 viu->dts+mx->video_delay,
00283 mx->SCR, mx->muxr, outbuf, &nlength,
00284 ptsdts, mx->vrbuffer);
00285
00286
00287 if (written == -1)
00288 return;
00289
00290 length -= nlength;
00291 dummy_add(&mx->vdbuf, uptsdiff( viu->dts+mx->video_delay,0)
00292 , viu->length-length);
00293 viu->length = length;
00294
00295
00296 viu->dts = uptsdiff(viu->dts + ((nlength*viu->ptsrate)>>8), 0);
00297
00298 write(mx->fd_out, outbuf, written);
00299
00300 #ifdef OUT_DEBUG
00301 LOG(VB_GENERAL, LOG_DEBUG, "VPTS");
00302 printpts(viu->pts);
00303 LOG(VB_GENERAL, LOG_DEBUG, " DTS");
00304 printpts(viu->dts);
00305 printpts(mx->video_delay);
00306 #endif
00307
00308 if (viu->length == 0){
00309 get_next_video_unit(mx, viu);
00310 }
00311
00312 }
00313
00314 static void writeout_ext(multiplex_t *mx, int n)
00315 {
00316 uint8_t outbuf[3000];
00317 int written=0;
00318 unsigned int length=0;
00319 int nlength=0;
00320 uint64_t pts, dpts=0;
00321 int newpts=0;
00322 int nframes=1;
00323 int ac3_off=0;
00324 int rest_data = 5;
00325
00326 int type = mx->ext[n].type;
00327 ringbuffer *airbuffer = &mx->index_extrbuffer[n];
00328 dummy_buffer *dbuf = &mx->ext[n].dbuf;
00329 uint64_t adelay = mx->ext[n].pts_off;
00330 uint64_t *apts = &mx->ext[n].pts;
00331 index_unit *aiu = &mx->ext[n].iu;
00332
00333 switch (type){
00334
00335 case MPEG_AUDIO:
00336 #ifdef OUT_DEBUG
00337 LOG(VB_GENERAL, LOG_DEBUG, "writing AUDIO%d pack\n", n);
00338 #endif
00339 break;
00340
00341 case AC3:
00342 #ifdef OUT_DEBUG
00343 LOG(VB_GENERAL, LOG_DEBUG, "writing AC3%d pack\n", n);
00344 #endif
00345 rest_data = 1;
00346 break;
00347
00348 default:
00349 return;
00350 }
00351
00352 if (mx->finish != 2 && dummy_space(dbuf) < mx->data_size + rest_data){
00353 return;
00354 }
00355
00356 pts = uptsdiff( aiu->pts + mx->audio_delay, adelay );
00357 *apts = pts;
00358 length = aiu->length;
00359 if (length < aiu->framesize){
00360 newpts = 1;
00361 ac3_off = length;
00362 }
00363 dummy_add(dbuf, pts, aiu->length);
00364
00365 #ifdef OUT_DEBUG
00366 LOG(VB_GENERAL, LOG_DEBUG, "start: %d stop: %d (%d) length %d",
00367 aiu->start, (aiu->start+aiu->length),
00368 aiu->length, length);
00369 printpts(*apts);
00370 printpts(aiu->pts);
00371 printpts(mx->audio_delay);
00372 printpts(adelay);
00373 printpts(pts);
00374 #endif
00375 while (!mx->is_ts && length < mx->data_size + rest_data){
00376 if (ring_read(airbuffer, (uint8_t *)aiu, sizeof(index_unit)) > 0){
00377 dpts = uptsdiff(aiu->pts +mx->audio_delay, adelay );
00378
00379 if (newpts){
00380 pts = dpts;
00381 newpts=0;
00382 }
00383
00384 length+= aiu->length;
00385 if (length < mx->data_size + rest_data)
00386 dummy_add(dbuf, dpts, aiu->length);
00387
00388 *apts = dpts;
00389 nframes++;
00390 #ifdef OUT_DEBUG
00391 LOG(VB_GENERAL, LOG_DEBUG,
00392 "start: %d stop: %d (%d) length %d",
00393 aiu->start, (aiu->start+aiu->length),
00394 aiu->length, length);
00395 printpts(*apts);
00396 printpts(aiu->pts);
00397 printpts(mx->audio_delay);
00398 printpts(adelay);
00399 #endif
00400 } else if (mx->finish){
00401 break;
00402 } else if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
00403 LOG(VB_GENERAL, LOG_ERR, "error in writeout ext");
00404 exit(1);
00405 }
00406 }
00407
00408 nlength = length;
00409
00410 switch (type) {
00411 case MPEG_AUDIO:
00412 if(mx->is_ts)
00413 written = write_audio_ts( mx->ext[n].strmnum, pts,
00414 outbuf, &nlength, newpts ? 0 : PTS_ONLY,
00415 &mx->extrbuffer[n]);
00416 else
00417 written = write_audio_pes( mx->pack_size, mx->extcnt,
00418 mx->ext[n].strmnum, pts, mx->SCR,
00419 mx->muxr, outbuf, &nlength, PTS_ONLY,
00420 &mx->extrbuffer[n]);
00421 break;
00422 case AC3:
00423 if(mx->is_ts)
00424 written = write_ac3_ts(mx->ext[n].strmnum, pts,
00425 outbuf, &nlength, newpts ? 0 : PTS_ONLY,
00426 mx->ext[n].frmperpkt, &mx->extrbuffer[n]);
00427 else
00428 written = write_ac3_pes( mx->pack_size, mx->extcnt,
00429 mx->ext[n].strmnum, pts, mx->SCR,
00430 mx->muxr, outbuf, &nlength, PTS_ONLY,
00431 nframes, ac3_off,
00432 &mx->extrbuffer[n]);
00433 break;
00434 }
00435
00436
00437
00438 if (written == -1)
00439 return;
00440
00441 length -= nlength;
00442 write(mx->fd_out, outbuf, written);
00443
00444 dummy_add(dbuf, dpts, aiu->length-length);
00445 aiu->length = length;
00446 aiu->start = ring_rpos(&mx->extrbuffer[n]);
00447
00448 if (aiu->length == 0){
00449 get_next_ext_unit(mx, aiu, n);
00450 } else {
00451
00452 aiu->pts = uptsdiff(aiu->pts + ((nlength*aiu->ptsrate)>>8), 0);
00453 }
00454 *apts = uptsdiff(aiu->pts + mx->audio_delay, adelay);
00455 #ifdef OUT_DEBUG
00456 if ((int64_t)*apts < 0)
00457 LOG(VB_GENERAL, LOG_DEBUG, "SCHEISS APTS");
00458 printpts(*apts);
00459 printpts(aiu->pts);
00460 printpts(mx->audio_delay);
00461 printpts(adelay);
00462 #endif
00463
00464 if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
00465 LOG(VB_GENERAL, LOG_ERR, "error in writeout ext");
00466 exit(1);
00467 }
00468 }
00469
00470 static void writeout_padding (multiplex_t *mx)
00471 {
00472 uint8_t outbuf[3000];
00473 #if 0
00474 LOG(VB_GENERAL, LOG_INFO, "writing PADDING pack");
00475 #endif
00476
00477 write_padding_pes( mx->pack_size, mx->extcnt, mx->SCR,
00478 mx->muxr, outbuf);
00479 write(mx->fd_out, outbuf, mx->pack_size);
00480 }
00481
00482 void check_times( multiplex_t *mx, int *video_ok, int *ext_ok, int *start)
00483 {
00484 int i;
00485 int set_ok = 0;
00486
00487 memset(ext_ok, 0, N_AUDIO*sizeof(int));
00488 *video_ok = 0;
00489
00490 if (mx->fill_buffers(mx->priv, mx->finish)< 0) {
00491 LOG(VB_GENERAL, LOG_ERR, "error in get next video unit");
00492 return;
00493 }
00494
00495
00496 mx->oldSCR = mx->SCR;
00497 if (!*start){
00498 ptsinc(&mx->SCR, mx->SCRinc);
00499 } else *start = 0;
00500
00501 if (mx->VBR) {
00502 #ifdef OUT_DEBUG1
00503 LOG(VB_GENERAL, LOG_DEBUG, "EXTRACLOCK: %lli", mx->extra_clock);
00504 printpts(mx->extra_clock);
00505 #endif
00506
00507 if (mx->extra_clock > 0.0) {
00508 int64_t d = mx->extra_clock/ mx->SCRinc - 1;
00509 if (d > 0)
00510 mx->extra_clock = d*mx->SCRinc;
00511 else
00512 mx->extra_clock = 0.0;
00513 }
00514
00515 if (mx->extra_clock > 0.0) {
00516 int64_t temp_scr = mx->extra_clock;
00517
00518 for (i=0; i<mx->extcnt; i++){
00519 if (ptscmp(mx->SCR + temp_scr + 100*CLOCK_MS,
00520 mx->ext[i].iu.pts) > 0) {
00521 while (ptscmp(mx->SCR + temp_scr
00522 + 100*CLOCK_MS,
00523 mx->ext[i].iu.pts) > 0)
00524 temp_scr -= mx->SCRinc;
00525 temp_scr += mx->SCRinc;
00526 }
00527 }
00528
00529 if (temp_scr > 0.0) {
00530 mx->SCR += temp_scr;
00531 mx->extra_clock -= temp_scr;
00532 } else
00533 mx->extra_clock = 0.0;
00534 }
00535 }
00536
00537
00538 dummy_delete(&mx->vdbuf, mx->SCR);
00539
00540 for (i=0;i <mx->extcnt; i++)
00541 dummy_delete(&mx->ext[i].dbuf, mx->SCR);
00542
00543 if (dummy_space(&mx->vdbuf) > mx->vsize && mx->viu.length > 0 &&
00544 (ptscmp(mx->viu.dts + mx->video_delay, 500*CLOCK_MS +mx->oldSCR)<0)
00545 && ring_avail(mx->index_vrbuffer)){
00546 *video_ok = 1;
00547 set_ok = 1;
00548 }
00549
00550 for (i = 0; i < mx->extcnt; i++){
00551 if (dummy_space(&mx->ext[i].dbuf) > mx->extsize &&
00552 mx->ext[i].iu.length > 0 &&
00553 ptscmp(mx->ext[i].pts, 500*CLOCK_MS + mx->oldSCR) < 0
00554 && ring_avail(&mx->index_extrbuffer[i])){
00555 ext_ok[i] = 1;
00556 set_ok = 1;
00557 }
00558 }
00559 #ifdef OUT_DEBUG
00560 if (set_ok) {
00561 LOG(VB_GENERAL, LOG_DEBUG, "SCR");
00562 printpts(mx->oldSCR);
00563 LOG(VB_GENERAL, LOG_DEBUG, "VDTS");
00564 printpts(mx->viu.dts);
00565 LOG(VB_GENERAL, LOG_DEBUG, " (%d) EXT", *video_ok);
00566 for (i = 0; i < mx->extcnt; i++){
00567 LOG(VB_GENERAL, LOG_DEBUG, "%d:", mx->ext[i].type);
00568 printpts(mx->ext[i].pts);
00569 LOG(VB_GENERAL, LOG_DEBUG, " (%d)", ext_ok[i]);
00570 }
00571 }
00572 #endif
00573 }
00574 void write_out_packs( multiplex_t *mx, int video_ok, int *ext_ok)
00575 {
00576 int i;
00577
00578 if (video_ok && use_video(mx->viu.dts + mx->video_delay,
00579 mx->ext, ext_ok, mx->extcnt)) {
00580 writeout_video(mx);
00581 } else {
00582 i = which_ext(mx->ext, ext_ok, mx->extcnt);
00583 int done=0;
00584 if(i>=0) {
00585 writeout_ext(mx, i);
00586 done = 1;
00587 }
00588 if (!done && !mx->VBR){
00589 writeout_padding(mx);
00590 }
00591 }
00592
00593 }
00594
00595 void finish_mpg(multiplex_t *mx)
00596 {
00597 int start=0;
00598 int video_ok = 0;
00599 int ext_ok[N_AUDIO];
00600 int n,nn,old,i;
00601 uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 };
00602
00603 memset(ext_ok, 0, N_AUDIO*sizeof(int));
00604 mx->finish = 1;
00605
00606 old = 0;nn=0;
00607 while ((n=buffers_filled(mx)) && nn<1000 ){
00608 if (n== old) nn++;
00609 else nn=0;
00610 old = n;
00611 check_times( mx, &video_ok, ext_ok, &start);
00612 write_out_packs( mx, video_ok, ext_ok);
00613 }
00614
00615 old = 0;nn=0;
00616 while ((n=ring_avail(mx->index_vrbuffer)/sizeof(index_unit))
00617 && nn<1000){
00618 if (n== old) nn++;
00619 else nn= 0;
00620 old = n;
00621 writeout_video(mx);
00622 }
00623
00624
00625 mx->finish = 2;
00626 old = 0;nn=0;
00627 for (i = 0; i < mx->extcnt; i++){
00628 while ((n=ring_avail(&mx->index_extrbuffer[i])/
00629 sizeof(index_unit)) && nn <100){
00630 if (n== old) nn++;
00631 else nn = 0;
00632 old = n;
00633 writeout_ext(mx, i);
00634 }
00635 }
00636
00637 if (mx->otype == REPLEX_MPEG2)
00638 write(mx->fd_out, mpeg_end,4);
00639
00640 dummy_destroy(&mx->vdbuf);
00641 for (i=0; i<mx->extcnt;i++)
00642 dummy_destroy(&mx->ext[i].dbuf);
00643 }
00644
00645 static int get_ts_video_overhead(int pktsize, sequence_t *seq)
00646 {
00647 uint32_t framesize;
00648 uint32_t numpkt;
00649 int pktdata = pktsize - TS_HEADER_MIN;
00650 framesize = seq->bit_rate * 50 / seq->frame_rate;
00651 numpkt = (framesize + PES_H_MIN + 10 + pktdata -1) / pktdata;
00652 return pktsize- ((pktsize * numpkt) - framesize + numpkt - 1) / numpkt;
00653 }
00654
00655 static int get_ts_ext_overhead(int pktsize, audio_frame_t *extframe,
00656 extdata_t *ext, int cnt)
00657 {
00658 int i, max = 0;
00659 int pktdata = pktsize - TS_HEADER_MIN;
00660 for (i = 0; i < cnt; i++) {
00661 int size, numpkt, overhead;
00662
00663
00664
00665 ext[i].frmperpkt = extframe[i].bit_rate / 53 /
00666 extframe[i].framesize;
00667 size = extframe[i].framesize * ext[i].frmperpkt;
00668 numpkt = (size + pktdata - 1) / pktdata;
00669 overhead = (pktsize * numpkt - size + numpkt - 1) / numpkt;
00670 if(overhead > max)
00671 max = overhead;
00672 }
00673 return pktsize - max;
00674 }
00675
00676 void init_multiplex( multiplex_t *mx, sequence_t *seq_head,
00677 audio_frame_t *extframe, int *exttype, int *exttypcnt,
00678 uint64_t video_delay, uint64_t audio_delay, int fd,
00679 int (*fill_buffers)(void *p, int f),
00680 ringbuffer *vrbuffer, ringbuffer *index_vrbuffer,
00681 ringbuffer *extrbuffer, ringbuffer *index_extrbuffer,
00682 int otype)
00683 {
00684 int i;
00685 uint32_t data_rate;
00686
00687 mx->fill_buffers = fill_buffers;
00688 mx->video_delay = video_delay;
00689 mx->audio_delay = audio_delay;
00690 mx->fd_out = fd;
00691 mx->otype = otype;
00692
00693 switch(mx->otype){
00694
00695 case REPLEX_DVD:
00696 mx->video_delay += 180*CLOCK_MS;
00697 mx->audio_delay += 180*CLOCK_MS;
00698 mx->pack_size = 2048;
00699 mx->audio_buffer_size = 4*1024;
00700 mx->video_buffer_size = 232*1024;
00701 mx->mux_rate = 1260000;
00702 mx->navpack = 1;
00703 mx->frame_timestamps = TIME_IFRAME;
00704 mx->VBR = 1;
00705 mx->reset_clocks = 0;
00706 mx->write_end_codes = 0;
00707 mx->set_broken_link = 0;
00708 mx->is_ts = 0;
00709 break;
00710
00711
00712 case REPLEX_MPEG2:
00713 mx->video_delay += 180*CLOCK_MS;
00714 mx->audio_delay += 180*CLOCK_MS;
00715 mx->pack_size = 2048;
00716 mx->audio_buffer_size = 4*1024;
00717 mx->video_buffer_size = 224*1024;
00718 mx->mux_rate = 0;
00719 mx->navpack = 0;
00720 mx->frame_timestamps = TIME_ALWAYS;
00721 mx->VBR = 1;
00722 mx->reset_clocks = 1;
00723 mx->write_end_codes = 1;
00724 mx->set_broken_link = 1;
00725 mx->is_ts = 0;
00726 break;
00727
00728 case REPLEX_HDTV:
00729 mx->video_delay += 180*CLOCK_MS;
00730 mx->audio_delay += 180*CLOCK_MS;
00731 mx->pack_size = 2048;
00732 mx->audio_buffer_size = 4*1024;
00733 mx->video_buffer_size = 4*224*1024;
00734 mx->mux_rate = 0;
00735 mx->navpack = 0;
00736 mx->frame_timestamps = TIME_ALWAYS;
00737 mx->VBR = 1;
00738 mx->reset_clocks = 1;
00739 mx->write_end_codes = 1;
00740 mx->set_broken_link = 1;
00741 mx->is_ts = 0;
00742 break;
00743
00744 case REPLEX_TS_SD:
00745 mx->video_delay += 180*CLOCK_MS;
00746 mx->audio_delay += 180*CLOCK_MS;
00747 mx->pack_size = 188;
00748 mx->audio_buffer_size = 4*1024;
00749 mx->video_buffer_size = 232*1024;
00750 mx->mux_rate = 1260000;
00751 mx->navpack = 0;
00752 mx->frame_timestamps = TIME_ALWAYS;
00753 mx->VBR = 1;
00754 mx->reset_clocks = 0;
00755 mx->write_end_codes = 0;
00756 mx->set_broken_link = 0;
00757 mx->is_ts = 1;
00758 break;
00759
00760 case REPLEX_TS_HD:
00761 mx->video_delay += 180*CLOCK_MS;
00762 mx->audio_delay += 180*CLOCK_MS;
00763 mx->pack_size = 188;
00764 mx->audio_buffer_size = 4*1024;
00765 mx->video_buffer_size = 4*224*1024;
00766 mx->mux_rate = 0;
00767 mx->navpack = 0;
00768 mx->frame_timestamps = TIME_ALWAYS;
00769 mx->VBR = 1;
00770 mx->reset_clocks = 0;
00771 mx->write_end_codes = 0;
00772 mx->set_broken_link = 0;
00773 mx->is_ts = 1;
00774 break;
00775 }
00776
00777 for (mx->extcnt = 0, data_rate = 0, i = 0;
00778 i < N_AUDIO && exttype[i]; i++){
00779 if (exttype[i] >= MAX_TYPES) {
00780 LOG(VB_GENERAL, LOG_ERR, "Found illegal stream type %d",
00781 exttype[i]);
00782 exit(1);
00783 }
00784 mx->ext[i].type = exttype[i];
00785 mx->ext[i].pts_off = 0;
00786 mx->ext[i].frmperpkt = 1;
00787 mx->ext[i].strmnum = exttypcnt[i];
00788 strncpy(mx->ext[i].language, extframe[i].language, 4);
00789 dummy_init(&mx->ext[i].dbuf, mx->audio_buffer_size);
00790 data_rate += extframe[i].bit_rate;
00791 mx->extcnt++;
00792 }
00793
00794 mx->vrbuffer = vrbuffer;
00795 mx->index_vrbuffer = index_vrbuffer;
00796 mx->extrbuffer = extrbuffer;
00797 mx->index_extrbuffer = index_extrbuffer;
00798
00799 dummy_init(&mx->vdbuf, mx->video_buffer_size);
00800
00801
00802
00803 if(mx->is_ts) {
00804
00805 mx->data_size = get_ts_video_overhead(mx->pack_size, seq_head);
00806 mx->extsize = get_ts_ext_overhead(mx->pack_size, extframe,
00807 mx->ext, mx->extcnt);
00808
00809 } else {
00810
00811 mx->data_size = mx->pack_size - PES_H_MIN - PS_HEADER_L1 - 10;
00812 mx->extsize = mx->data_size + 5;
00813 }
00814 mx->vsize = mx->data_size;
00815
00816 data_rate += seq_head->bit_rate *400;
00817
00818 mx->muxr = ((uint64_t)data_rate / 8 * mx->pack_size) / mx->data_size;
00819
00820
00821 if (mx->mux_rate) {
00822 if ( mx->mux_rate < mx->muxr)
00823 LOG(VB_GENERAL, LOG_WARNING,
00824 "data rate may be to high for required mux rate");
00825 mx->muxr = mx->mux_rate;
00826 }
00827 LOG(VB_GENERAL, LOG_INFO, "Mux rate: %.2f Mbit/s",
00828 mx->muxr*8.0/1000000.0);
00829
00830 mx->SCRinc = 27000000ULL/((uint64_t)mx->muxr /
00831 (uint64_t) mx->pack_size);
00832
00833 }
00834
00835 void setup_multiplex(multiplex_t *mx)
00836 {
00837 int i;
00838
00839 get_next_video_unit(mx, &mx->viu);
00840 for (i=0; i < mx->extcnt; i++)
00841 {
00842 get_next_ext_unit(mx, &mx->ext[i].iu, i);
00843 if (mx->ext[i].type == MPEG_AUDIO || mx->ext[i].type == AC3)
00844 mx->ext[i].pts = uptsdiff(
00845 mx->ext[i].iu.pts + mx->audio_delay,
00846 mx->ext[i].pts_off);
00847 else
00848 mx->ext[i].pts = uptsdiff(
00849 mx->ext[i].iu.pts, mx->ext[i].pts_off);
00850 }
00851
00852 mx->SCR = 0;
00853
00854
00855 if (mx->is_ts) {
00856 uint8_t outbuf[2048];
00857 write_ts_patpmt(mx->ext, mx->extcnt, 1, outbuf);
00858 write(mx->fd_out, outbuf, mx->pack_size*2);
00859 ptsinc(&mx->SCR, mx->SCRinc*2);
00860 mx->startup = 1;
00861 } else if (mx->navpack){
00862 uint8_t outbuf[2048];
00863 write_nav_pack(mx->pack_size, mx->extcnt,
00864 mx->SCR, mx->muxr, outbuf);
00865 write(mx->fd_out, outbuf, mx->pack_size);
00866 ptsinc(&mx->SCR, mx->SCRinc);
00867 mx->startup = 1;
00868 } else mx->startup = 0;
00869 }