|
MythTV
0.26-pre
|
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 //left-shift by 8 to increase precision 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 //left-shift by 8 to increase precision 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 // something bad happened with the PES or TS write, bail 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 //estimate next pts based on bitrate of this stream and data written 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; // 4 bytes AC3 header 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 // something bad happened when writing TS or PES to the MPEG or AC3 00437 // audio stream 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 //estimate next pts based on bitrate of stream and data written 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 /* increase SCR to next packet */ 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 /* clear decoder buffers up to SCR */ 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 { // second case(s): audio ok, video in time 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 // flush the rest 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; //avg bytes/frame 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 // 1/53 is approx 0.15 * 1/8 which allows us to calculate the 00663 // # of packets in .15 seconds (which is the number of packets 00664 // per PES. 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 //NOTE: vpkt_hdr/extpkt_hdr are worst-case for PS streams, but 00802 //best-guess for TS streams 00803 if(mx->is_ts) { 00804 //Use best guess for TS streams 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 //Use worst case for PS streams 00811 mx->data_size = mx->pack_size - PES_H_MIN - PS_HEADER_L1 - 10; 00812 mx->extsize = mx->data_size + 5; //one less DTS 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 // muxrate of payload in Byte/s 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 // write first VOBU header 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 }
1.7.6.1