#include #include #include #include #include #include #include #include "libzmpeg3.h" const char *prog = 0; int vtrk = 0; int verbose = 0; int wdw_mask = -1; int cc_service = 1; int done = 0; long fpos = 0; char dfrm[1000]; int dlen = 0; long dsofs = 0, deofs = 0; char *xfn = 0, *ofn = 0; FILE *xfp = 0, *ofp = 0; class Edit { long start, length; long offset; public: static int cmpr(const void *ap, const void *bp); Edit(long st, long len, long ofs) : start(st), length(len), offset(ofs) {} long sfrm() { return start; } long efrm() { return start+length-1; } long ofrm(long frm) { return frm-start+offset; } ~Edit() {} }; int Edit::cmpr(const void *ap, const void *bp) { Edit *a = *(Edit **)ap; Edit *b = *(Edit **)bp; int n = a->sfrm() - b->sfrm(); if( !n ) n = a->length - b->length; return n; } class Edits { int count, allocated; Edit **list; long pos; public: Edits() : count(0), allocated(0), list(0), pos(0) {} ~Edits() { for( int i=0; i0 && frm>=list[count-1]->efrm(); } Edit *active(long frm); void sort() { qsort(list, count, sizeof(Edit*), Edit::cmpr); } int len() { return count; } } edits; void Edits::append(long st, long len) { if( count >= allocated ) { int sz = 2*allocated + 16; Edit **new_list = new Edit*[sz]; for( int i=0; i 1 ) { int m = (l+h) >> 1; mp = list[m]; if( frm < mp->sfrm() ) l = m; else if( frm > mp->sfrm() ) h = m; else break; } if( !mp ) return 0; if( frm < mp->sfrm() ) return 0; if( frm > mp->efrm() ) return 0; return mp; } void usage() { fprintf(stderr,"usage: %s ",prog); fprintf(stderr," [-c cc_service ] "); fprintf(stderr," [-s start:length, ...] "); fprintf(stderr," [ -t track ] "); fprintf(stderr," [-v verbose ]\n"); fprintf(stderr," "); fprintf(stderr," [-w wdw mask ] "); fprintf(stderr," [-x file.xml ] "); fprintf(stderr," [-o file.udvd ] "); fprintf(stderr," file.ts\n"); fprintf(stderr," cc_service = closed caption service id\n"); fprintf(stderr," start:length = start:length frames (comma seperated list)\n"); fprintf(stderr," track = video track number\n"); fprintf(stderr," verbose = verbose level\n"); fprintf(stderr," wdw mask = bit mask for windows (-1 = all)\n"); fprintf(stderr," file.xml = filename for edl xml format subtitle data\n"); fprintf(stderr," file.udvd = filename for udvd format subtitle data\n"); fprintf(stderr," file.ts = filename for transport stream\n"); exit(1); } void edl_header() { fprintf(xfp,"\n"); fprintf(xfp,"\n", xfn); fprintf(xfp," \n"); fprintf(xfp,"Subttl 1\n"); fprintf(xfp,"\n"); } void edit_data(const char *sp, int n, int len) { const char *cp, *ep = sp + n; fprintf(xfp,"': cp = ">"; break; case '&': cp = "&"; break; case '"': cp = """; break; default: fputc(ch, xfp); continue; } while( *cp != 0 ) fputc(*cp++, xfp); } fprintf(xfp,"\">\n"); } void edit_write() { if( !xfp ) return; long df; if( (df=dsofs-fpos) > 0 ) edit_data("", 0, df); if( (df=deofs-dsofs) > 0 ) edit_data(dfrm, dlen, df); fpos = deofs; } void edl_trailer() { if( dlen > 0 ) edit_write(); fprintf(xfp,"\n"); fprintf(xfp,"\n"); fprintf(xfp,"\n"); } int text_cb(int sid, int id, int sfrm, int efrm, const char *txt) { long sofs = sfrm, eofs = efrm; if( ((1< 0 ) { Edit *edit = edits.active(sfrm); if( !edit ) return 0; long frm; if( sfrm < (frm=edit->sfrm()) ) sfrm = frm; if( efrm > (frm=edit->efrm()) ) efrm = frm; sofs = edit->ofrm(sfrm); eofs = edit->ofrm(efrm); } // ltrim, rtrim data const char *bp, *cp; for( bp=txt; *bp; ++bp ) if( !isblank(*bp) && *bp != '|' ) break; if( !*bp ) return 0; const char *ep = bp; for( cp=bp; *cp; ++cp ) if( !isblank(*cp) && *cp != '|' ) ep = cp; int n = ep - bp + 1; // logging if( verbose ) { if( verbose > 2 ) fprintf(stderr,"\r"); fprintf(stderr,"%d",sfrm); if( verbose > 1 ) fprintf(stderr,": %*.*s", n, n, bp); fprintf(stderr,"\n"); } // output txt directly if( ofp && sofs < eofs ) { fprintf(ofp, "{%ld}{%ld}%*.*s\n", sofs, eofs-1, n, n, bp); } // last dfrm expired, output edit_data + reset dfrm if( sofs >= deofs ) { if( dlen > 0 ) edit_write(); dlen = 0; dsofs = sofs; } // append overlapping timeline data if( dlen > 0 && dlen < (int)sizeof(dfrm) ) dfrm[dlen++] = '|'; while( bp <= ep && dlen < (int)sizeof(dfrm) ) dfrm[dlen++] = *bp++; if( eofs > deofs ) deofs = eofs; return 0; } int main(int ac, char *av[]) { char *cp = 0, *fn = 0; prog = *av++; while( --ac > 0 ) { fn = *av++; if( *fn == '-' ) { switch( fn[1] ) { case 'c': if( --ac <= 0 ) usage(); cc_service = atoi(*av++); break; case 's': if( --ac <= 0 ) usage(); for( cp=*av++; *cp; ++cp ) { int st = strtol(cp,&cp,0); int len = *cp == ':' ? strtol(cp+1,&cp,0) : INT_MAX; edits.append(st,len); if( *cp != ',' ) break; } if( *cp ) { fprintf(stderr,"edit list error at: %s\n",cp); usage(); } edits.sort(); break; case 't': if( --ac <= 0 ) usage(); vtrk = atoi(*av++); break; case 'v': if( --ac <= 0 ) usage(); verbose = atoi(*av++); break; case 'o': if( --ac <= 0 ) usage(); ofn = *av++; break; case 'x': if( --ac <= 0 ) usage(); xfn = *av++; break; case 'w': if( --ac <= 0 ) usage(); wdw_mask = strtoul(*av++,0,0); if( !wdw_mask ) { fprintf(stderr,"no windows in bitmask\n"); exit(1); } break; default: usage(); } continue; } if( ac > 1 ) usage(); if( !access(fn,R_OK) ) break; fprintf(stderr, "no file %s\n", fn); exit(0); } if( !fn ) usage(); setbuf(stderr, 0); if( !xfn && !ofn ) { fprintf(stderr,"no output file (-x,-o) in command line arguments\n"); usage(); } if( xfn && ofn && !strcmp(xfn,ofn) ) { fprintf(stderr,"output files (-x,-o) overlap command line arguments\n"); usage(); } if( ofn ) { if( !strcmp(ofn,"-") ) ofp = stdout; else if( !(ofp=fopen(ofn,"w")) ) { perror(ofn); usage(); } } if( xfn ) { if( !strcmp(xfn,"-") ) xfp = stdout; else if( !(xfp=fopen(xfn,"w")) ) { perror(xfn); usage(); } } zmpeg3_t *in; int error = 0; if( !(in = mpeg3_open(fn, &error)) ) { fprintf(stderr, "unable to open %s\n", fn); exit(1); } if( !in->is_transport_stream() ) { fprintf(stderr, "not transport stream %s\n", fn); exit(1); } if( !mpeg3_has_video(in) ) { fprintf(stderr, "no video %s\n", fn); exit(1); } mpeg3_set_cpus(in, 8); int ctrk = cc_service-1; if( ctrk < 0 ) ctrk = 63; mpeg3_show_subtitle(in, vtrk, ctrk); if( mpeg3_set_cc_text_callback(in, vtrk, text_cb) ) { fprintf(stderr, "no video track %d on %s\n", vtrk, fn); exit(1); } if( xfp ) edl_header(); char *yp, *up, *vp; while( !done && !mpeg3_read_yuvframe_ptr(in, &yp, &up, &vp, vtrk) ) if( verbose > 2 ) fprintf(stderr," \r%ld", mpeg3_get_frame(in, vtrk)); if( xfp ) edl_trailer(); mpeg3_close(in); exit(0); }