MythTV  0.26-pre
multiplex.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends