source: tools/xupnpd/ts.cpp @ 35280

Last change on this file since 35280 was 34374, checked in by Stephan, 9 years ago

add xupnpd

File size: 20.6 KB
Line 
1/*
2
3 Copyright (C) 2009 Anton Burdinuk
4
5 clark15b@gmail.com
6
7*/
8
9
10#include "ts.h"
11
12// TODO: join TS
13
14// 1) M2TS timecode (0-1073741823)
15/*
16The extra 4-byte header is composed of two fields. The upper 2 bits are the copy_permission_indicator and the lower 30 bits are the arrival_time_stamp. The arrival_time_stamp is equal to the lower 30 bits of the 27 MHz STC at the 0x47 byte of the Transport packet. In a packet that contains a PCR, the PCR will be a few ticks later than the arrival_time_stamp. The exact difference between the arrival_time_stamp and the PCR (and the number of bits between them) indicates the intended fixed bitrate of the variable rate Transport Stream.
17
18The primary function is to allow the variable rate Transport Stream to be converted to a fixed rate stream before decoding (since only fixed rate Transport Streams fit into the T-STD buffering model).
19
20It doesn't really help for random access. 30 bits at 27 MHz only represents 39.77 seconds.
21*/
22
23// 2) TS Continuity counter (0-15..0-15..)
24// 3) PES PTS/DTS
25
26namespace ts
27{
28    void get_prefix_name_by_filename(const std::string& s,std::string& name);
29#ifdef _WIN32
30    void my_strptime(const char* s,tm* t);
31#endif
32}
33
34ts::stream::~stream(void)
35{
36    if(timecodes)
37        fclose(timecodes);
38}
39
40
41void ts::get_prefix_name_by_filename(const std::string& s,std::string& name)
42{
43    int ll=s.length();
44    const char* p=s.c_str();
45
46    while(ll>0)
47    {
48        if(p[ll-1]=='/' || p[ll-1]=='\\')
49            break;
50        ll--;
51    }
52
53    p+=ll;
54
55    int cn=0;
56
57    const char* pp=strchr(p,'.');
58
59    if(pp)
60        name.assign(p,pp-p);
61}
62
63
64ts::file::~file(void)
65{
66    close();
67}
68
69bool ts::file::open(int mode,const char* fmt,...)
70{
71    filename.clear();
72
73    char name[512];
74
75    va_list ap;
76    va_start(ap,fmt);
77    vsprintf(name,fmt,ap);
78    va_end(ap);
79
80    int flags=0;
81
82    switch(mode)
83    {
84    case in:
85        flags=O_LARGEFILE|O_BINARY|O_RDONLY;
86        break;
87    case out:
88        flags=O_CREAT|O_TRUNC|O_LARGEFILE|O_BINARY|O_WRONLY;
89        break;
90    }
91
92    fd=::open(name,flags,0644);
93
94    if(fd!=-1)
95    {
96        filename=name;
97        len=offset=0;
98        return true;
99    }
100
101    fprintf(stderr,"can`t open file %s\n",name);
102
103    return false;
104}
105
106
107void ts::file::close(void)
108{
109    if(fd!=-1)
110    {
111        flush();
112        ::close(fd);
113        fd=-1;
114    }
115    len=0;
116    offset=0;
117}
118
119int ts::file::flush(void)
120{
121    int l=0;
122
123    while(l<len)
124    {
125        int n=::write(fd,buf+l,len-l);
126        if(!n || n==-1)
127            break;
128        l+=n;
129    }
130
131    len=0;
132
133    return l;
134}
135
136int ts::file::write(const char* p,int l)
137{
138    int rc=l;
139
140    while(l>0)
141    {
142        if(len>=max_buf_len)
143            flush();
144
145        int n=max_buf_len-len;
146
147        if(n>l)
148            n=l;
149
150        memcpy(buf+len,p,n);
151        len+=n;
152
153        p+=n;
154        l-=n;
155    }
156
157    return rc;
158}
159int ts::file::read(char* p,int l)
160{
161    const char* tmp=p;
162
163    while(l>0)
164    {
165        int n=len-offset;
166
167        if(n>0)
168        {
169            if(n>l)
170                n=l;
171
172            memcpy(p,buf+offset,n);
173            p+=n;
174            offset+=n;
175            l-=n;
176        }else
177        {
178            int m=::read(fd,buf,max_buf_len);
179            if(m==-1 || !m)
180                break;
181            len=m;
182            offset=0;
183        }
184    }
185
186    return p-tmp;
187}
188
189
190bool ts::demuxer::validate_type(u_int8_t type)
191{
192    if(av_only)
193        return strchr("\x01\x02\x80\x1b\xea\x81\x06\x83\x03\x04\x82\x86\x8a",type)?true:false;
194
195    return true;
196}
197
198int ts::demuxer::get_stream_type(u_int8_t type)
199{
200    switch(type)
201    {
202    case 0x01:
203    case 0x02:
204        return stream_type::mpeg2_video;
205    case 0x80:
206        return hdmv?stream_type::lpcm_audio:stream_type::mpeg2_video;
207    case 0x1b:
208        return stream_type::h264_video;
209    case 0xea:
210        return stream_type::vc1_video;
211    case 0x81:
212    case 0x06:
213    case 0x83:
214        return stream_type::ac3_audio;
215    case 0x03:
216    case 0x04:
217        return stream_type::mpeg2_audio;
218    case 0x82:
219    case 0x86:
220    case 0x8a:
221        return stream_type::dts_audio;
222    }
223    return stream_type::data;
224}
225
226const char* ts::demuxer::get_stream_ext(u_int8_t type_id)
227{
228    static const char* list[8]= { "sup", "m2v", "264", "vc1", "ac3", "m2a", "pcm", "dts" };
229
230    if(type_id<0 || type_id>=8)
231        type_id=0;
232
233    return list[type_id];
234}
235
236u_int64_t ts::demuxer::decode_pts(const char* ptr)
237{
238    const unsigned char* p=(const unsigned char*)ptr;
239
240    u_int64_t pts=((p[0]&0xe)<<29);
241    pts|=((p[1]&0xff)<<22);
242    pts|=((p[2]&0xfe)<<14);
243    pts|=((p[3]&0xff)<<7);
244    pts|=((p[4]&0xfe)>>1);
245
246    return pts;
247}
248
249int ts::demuxer::demux_ts_packet(const char* ptr)
250{
251    u_int32_t timecode=0;
252    if(hdmv)
253    {
254        timecode=to_int32(ptr)&0x3fffffff;
255        ptr+=4;
256    }
257
258    const char* end_ptr=ptr+188;
259
260    if(ptr[0]!=0x47)            // ts sync byte
261        return -1;
262
263    u_int16_t pid=to_int(ptr+1);
264    u_int8_t flags=to_byte(ptr+3);
265
266    bool transport_error=pid&0x8000;
267    bool payload_unit_start_indicator=pid&0x4000;
268    bool adaptation_field_exist=flags&0x20;
269    bool payload_data_exist=flags&0x10;
270    u_int8_t continuity_counter=flags&0x0f;
271    pid&=0x1fff;
272
273    if(transport_error)
274        return -2;
275
276    if(pid==0x1fff || !payload_data_exist)
277        return 0;
278
279    ptr+=4;
280
281    // skip adaptation field
282    if(adaptation_field_exist)
283    {
284        ptr+=to_byte(ptr)+1;
285        if(ptr>=end_ptr)
286            return -3;
287    }
288
289    if(dump==1)
290        printf("%.4x: [%c%c%c%c] %u.%i\n",
291            pid,
292            transport_error?'e':'-',
293            payload_data_exist?'p':'-',
294            payload_unit_start_indicator?'s':'-',
295            adaptation_field_exist?'a':'-',
296            timecode,
297            continuity_counter
298            );
299
300
301    stream& s=streams[pid];
302
303    if(!pid || (s.channel!=0xffff && s.type==0xff))
304    {
305        // PSI
306
307        if(payload_unit_start_indicator)
308        {
309            // begin of PSI table
310
311            ptr++;
312
313            if(ptr>=end_ptr)
314                return -4;
315
316            if(*ptr!=0x00 && *ptr!=0x02)
317                return 0;
318
319            if(end_ptr-ptr<3)
320                return -5;
321
322            u_int16_t l=to_int(ptr+1);
323
324            if(l&0x3000!=0x3000)
325                return -6;
326
327            l&=0x0fff;
328
329            ptr+=3;
330
331            int len=end_ptr-ptr;
332
333            if(l>len)
334            {
335                if(l>ts::table::max_buf_len)
336                    return -7;
337
338                s.psi.reset();
339
340                memcpy(s.psi.buf,ptr,len);
341                s.psi.offset+=len;
342                s.psi.len=l;
343
344                return 0;
345            }else
346                end_ptr=ptr+l;
347        }else
348        {
349            // next part of PSI
350            if(!s.psi.offset)
351                return -8;
352
353            int len=end_ptr-ptr;
354
355            if(len>ts::table::max_buf_len-s.psi.offset)
356                return -9;
357
358            memcpy(s.psi.buf+s.psi.offset,ptr,len);
359            s.psi.offset+=len;
360
361            if(s.psi.offset<s.psi.len)
362                return 0;
363            else
364            {
365                ptr=s.psi.buf;
366                end_ptr=ptr+s.psi.len;
367            }
368        }
369
370        if(!pid)
371        {
372            // PAT
373
374            ptr+=5;
375
376            if(ptr>=end_ptr)
377                return -10;
378
379            int len=end_ptr-ptr-4;
380
381            if(len<0 || len%4)
382                return -11;
383
384            int n=len/4;
385
386            for(int i=0;i<n;i++,ptr+=4)
387            {
388                u_int16_t channel=to_int(ptr);
389                u_int16_t pid=to_int(ptr+2);
390
391                if(pid&0xe000!=0xe000)
392                    return -12;
393
394                pid&=0x1fff;
395
396                if(!demuxer::channel || demuxer::channel==channel)
397                {
398                    stream& ss=streams[pid];
399                    ss.channel=channel;
400                    ss.type=0xff;
401                }
402            }
403        }else
404        {
405            // PMT
406
407            ptr+=7;
408
409            if(ptr>=end_ptr)
410                return -13;
411
412            u_int16_t info_len=to_int(ptr)&0x0fff;
413
414            ptr+=info_len+2;
415            end_ptr-=4;
416
417            if(ptr>=end_ptr)
418                return -14;
419
420            while(ptr<end_ptr)
421            {
422                if(end_ptr-ptr<5)
423                    return -15;
424
425                u_int8_t type=to_byte(ptr);
426                u_int16_t pid=to_int(ptr+1);
427
428                if(pid&0xe000!=0xe000)
429                    return -16;
430
431                pid&=0x1fff;
432
433                info_len=to_int(ptr+3)&0x0fff;
434
435                ptr+=5+info_len;
436
437                // ignore unknown streams
438                if(validate_type(type))
439                {
440                    stream& ss=streams[pid];
441
442                    if(ss.channel!=s.channel || ss.type!=type)
443                    {
444                        ss.channel=s.channel;
445                        ss.type=type;
446                        ss.id=++s.id;
447
448                        if(!parse_only && !ss.file.is_opened())
449                        {
450                            if(dst.length())
451                                ss.file.open(file::out,"%s%c%strack_%i.%s",dst.c_str(),os_slash,prefix.c_str(),pid,get_stream_ext(get_stream_type(ss.type)));
452                            else
453                                ss.file.open(file::out,"%strack_%i.%s",prefix.c_str(),pid,get_stream_ext(get_stream_type(ss.type)));
454                        }
455                    }
456                }
457            }
458
459            if(ptr!=end_ptr)
460                return -18;
461        }
462    }else
463    {
464        if(s.type!=0xff)
465        {
466            // PES
467
468            if(payload_unit_start_indicator)
469            {
470                s.psi.reset();
471                s.psi.len=9;
472            }
473
474            while(s.psi.offset<s.psi.len)
475            {
476                int len=end_ptr-ptr;
477
478                if(len<=0)
479                    return 0;
480
481                int n=s.psi.len-s.psi.offset;
482
483                if(len>n)
484                    len=n;
485
486                memcpy(s.psi.buf+s.psi.offset,ptr,len);
487                s.psi.offset+=len;
488
489                ptr+=len;
490
491                if(s.psi.len==9)
492                    s.psi.len+=to_byte(s.psi.buf+8);
493            }
494
495            if(s.psi.len)
496            {
497                if(memcmp(s.psi.buf,"\x00\x00\x01",3))
498                    return -19;
499
500                s.stream_id=to_byte(s.psi.buf+3);
501
502                u_int8_t flags=to_byte(s.psi.buf+7);
503
504                s.frame_num++;
505
506                switch(flags&0xc0)
507                {
508                case 0x80:          // PTS only
509                    {
510                        u_int64_t pts=decode_pts(s.psi.buf+9);
511
512                        if(dump==2)
513                            printf("%.4x: %llu\n",pid,pts);
514                        else if(dump==3)
515                            printf("%.4x: track=%.4x.%.2i, type=%.2x, stream=%.2x, pts=%llums\n",pid,s.channel,s.id,s.type,s.stream_id,pts/90);
516
517                        if(s.dts>0 && pts>s.dts)
518                            s.frame_length=pts-s.dts;
519                        s.dts=pts;
520
521                        if(pts>s.last_pts)
522                            s.last_pts=pts;
523
524                        if(!s.first_pts)
525                            s.first_pts=pts;
526                    }
527                    break;
528                case 0xc0:          // PTS,DTS
529                    {
530                        u_int64_t pts=decode_pts(s.psi.buf+9);
531                        u_int64_t dts=decode_pts(s.psi.buf+14);
532
533                        if(dump==2)
534                            printf("%.4x: %llu %llu\n",pid,pts,dts);
535                        else if(dump==3)
536                            printf("%.4x: track=%.4x.%.2i, type=%.2x, stream=%.2x, pts=%llums, dts=%llums\n",pid,s.channel,s.id,s.type,s.stream_id,pts/90,dts/90);
537
538                        if(s.dts>0 && dts>s.dts)
539                            s.frame_length=dts-s.dts;
540                        s.dts=dts;
541
542                        if(pts>s.last_pts)
543                            s.last_pts=pts;
544
545                        if(!s.first_dts)
546                            s.first_dts=dts;
547                    }
548                    break;
549                }
550
551                if(pes_output && s.file.is_opened())
552                    s.file.write(s.psi.buf,s.psi.len);
553
554                s.psi.reset();
555            }
556
557            if(s.frame_num)
558            {
559                int len=end_ptr-ptr;
560
561                if(es_parse)
562                {
563                    switch(s.type)
564                    {
565                    case 0x1b:
566                        s.frame_num_h264.parse(ptr,len);
567                        break;
568                    case 0x06:
569                    case 0x81:
570                    case 0x83:
571                        s.frame_num_ac3.parse(ptr,len);
572                        break;
573                    }
574                }
575
576                if(s.file.is_opened())
577                    s.file.write(ptr,len);
578            }
579        }
580    }
581
582    return 0;
583}
584
585void ts::demuxer::show(void)
586{
587    u_int64_t beg_pts=0,end_pts=0;
588
589    for(std::map<u_int16_t,ts::stream>::const_iterator i=streams.begin();i!=streams.end();++i)
590    {
591        const ts::stream& s=i->second;
592
593        if(s.type!=0xff)
594        {
595            if(s.first_pts<beg_pts || !beg_pts)
596                beg_pts=s.first_pts;
597
598            u_int64_t n=s.last_pts+s.frame_length;
599            if(n>end_pts || !end_pts)
600                end_pts=n;
601        }
602    }
603
604    for(std::map<u_int16_t,ts::stream>::const_iterator i=streams.begin();i!=streams.end();++i)
605    {
606        u_int16_t pid=i->first;
607        const ts::stream& s=i->second;
608
609        if(s.type!=0xff)
610        {
611            u_int64_t end=s.last_pts+s.frame_length;
612            u_int64_t len=end-s.first_pts;
613
614            fprintf(stderr,"pid=%i (0x%.4x), ch=%i, id=%.i, type=0x%.2x (%s), stream=0x%.2x",
615                pid,pid,s.channel,s.id,s.type,get_stream_ext(get_stream_type(s.type)),s.stream_id);
616
617            if(s.frame_length>0)
618                fprintf(stderr,", fps=%.2f",90000./(double)s.frame_length);
619
620            if(len>0)
621                fprintf(stderr,", len=%llums",len/90);
622
623
624            if(s.frame_num>0)
625                fprintf(stderr,", fn=%llu",s.frame_num);
626
627            u_int64_t esfn=s.get_es_frame_num();
628
629            if(esfn>0)
630                fprintf(stderr,", esfn=%llu",esfn);
631
632            if(s.first_pts>beg_pts)
633            {
634                u_int32_t n=(s.first_pts-beg_pts)/90;
635
636                fprintf(stderr,", head=+%ums",n);
637            }
638
639            if(end<end_pts)
640            {
641                u_int32_t n=(end_pts-end)/90;
642
643                fprintf(stderr,", tail=-%ums",n);
644            }
645
646            fprintf(stderr,"\n");
647        }
648    }
649}
650
651int ts::demuxer::demux_file(const char* name)
652{
653    prefix.clear();
654
655    char buf[192];
656
657    int buf_len=0;
658
659    ts::file file;
660
661    if(!file.open(file::in,"%s",name))
662    {
663        fprintf(stderr,"can`t open file %s\n",name);
664        return -1;
665    }
666
667    get_prefix_name_by_filename(name,prefix);
668    if(prefix.length())
669        prefix+='.';
670
671    for(u_int64_t pn=1;;pn++)
672    {
673        if(buf_len)
674        {
675            if(file.read(buf,buf_len)!=buf_len)
676                break;
677        }else
678        {
679            if(file.read(buf,188)!=188)
680                break;
681            if(buf[0]==0x47 && buf[4]!=0x47)
682            {
683                buf_len=188;
684                fprintf(stderr,"TS stream detected in %s (packet length=%i)\n",name,buf_len);
685                hdmv=false;
686            }else if(buf[0]!=0x47 && buf[4]==0x47)
687            {
688                if(file.read(buf+188,4)!=4)
689                    break;
690                buf_len=192;
691                fprintf(stderr,"M2TS stream detected in %s (packet length=%i)\n",name,buf_len);
692                hdmv=true;
693            }else
694            {
695                fprintf(stderr,"unknown stream type in %s\n",name);
696                return -1;
697            }
698        }
699
700        int n;
701        if((n=demux_ts_packet(buf)))
702        {
703            fprintf(stderr,"%s: invalid packet %llu (%i)\n",name,pn,n);
704            return -1;
705        }
706    }
707
708    return 0;
709}
710
711#ifdef _WIN32
712void ts::my_strptime(const char* s,tm* t)
713{
714    memset((char*)t,0,sizeof(tm));
715    sscanf(s,"%d-%d-%d %d:%d:%d",&t->tm_year,&t->tm_mon,&t->tm_mday,&t->tm_hour,&t->tm_min,&t->tm_sec);
716    t->tm_year-=1900;
717    t->tm_mon-=1;
718    t->tm_isdst=1;
719}
720#endif
721
722int ts::demuxer::gen_timecodes(const std::string& datetime)
723{
724    u_int64_t beg_pts=0;
725    u_int64_t end_pts=0;
726
727    for(std::map<u_int16_t,stream>::iterator i=streams.begin();i!=streams.end();++i)
728    {
729        u_int16_t pid=i->first;
730        ts::stream& s=i->second;
731
732        if(s.type!=0xff)
733        {
734            if(!s.timecodes && s.file.filename.length())
735            {
736                std::string::size_type n=s.file.filename.find_last_of('.');
737                if(n!=std::string::npos)
738                {
739                    std::string filename=s.file.filename.substr(0,n);
740                    filename+=".tmc";
741
742                    s.timecodes=fopen(filename.c_str(),"w");
743
744                    if(s.timecodes)
745                        fprintf(s.timecodes,"# timecode format v2\n");
746                }
747            }
748            if(s.timecodes)
749            {
750                if(s.first_pts<beg_pts || !beg_pts)
751                    beg_pts=s.first_pts;
752
753                u_int64_t len=s.last_pts+s.frame_length;
754
755                if(len>end_pts || !end_pts)
756                    end_pts=len;
757            }
758        }
759    }
760
761
762    for(std::map<u_int16_t,stream>::iterator i=streams.begin();i!=streams.end();++i)
763    {
764        u_int16_t pid=i->first;
765        ts::stream& s=i->second;
766
767        if(s.timecodes)
768        {
769            u_int64_t esfn=s.get_es_frame_num();
770
771            u_int64_t frame_num=esfn?esfn:s.frame_num;
772
773#ifdef OLD_TIMECODES
774            write_timecodes(s.timecodes,base_pts+(s.first_pts-beg_pts),base_pts+(s.last_pts+s.frame_length-beg_pts),frame_num,s.frame_length);
775#else
776            switch(get_stream_type(s.type))
777            {
778            case stream_type::ac3_audio:
779            case stream_type::mpeg2_audio:
780            case stream_type::lpcm_audio:
781                write_timecodes2(s.timecodes,base_pts+(s.first_pts-beg_pts),base_pts+(s.last_pts+s.frame_length-beg_pts),frame_num,s.frame_length);
782                break;
783            default:
784                write_timecodes(s.timecodes,base_pts+(s.first_pts-beg_pts),base_pts+(s.last_pts+s.frame_length-beg_pts),frame_num,s.frame_length);
785                break;
786            }
787#endif
788        }
789    }
790
791    if(!subs && datetime.length())
792    {
793        char path[512];
794        sprintf(path,"%s%ctimecodes.srt",dst.c_str(),os_slash);
795
796        subs=fopen(path,"w");
797
798        if(subs)
799            subs_filename=path;
800    }
801
802    u_int64_t length=end_pts-beg_pts;
803
804    if(subs && datetime.length())
805    {
806        u_int32_t cur=base_pts/90;
807
808        u_int32_t num=(length/90)/1000;
809
810        time_t timecode=0;
811
812        tm t;
813#ifdef _WIN32
814        my_strptime(datetime.c_str(),&t);
815#else
816        strptime(datetime.c_str(),"%Y-%m-%d %H:%M:%S",&t);
817#endif
818        timecode=mktime(&t);
819
820        for(u_int32_t i=0;i<num;i++)
821        {
822            std::string start=ts::timecode_to_time(cur);
823
824            if(i<num-1)
825                cur+=1000;
826            else
827                cur=(base_pts+length)/90;
828
829            std::string end=ts::timecode_to_time(cur-1);
830
831            start[8]=',';
832            end[8]=',';
833
834#ifdef _WIN32
835            localtime_s(&t,&timecode);
836#else
837            localtime_r(&timecode,&t);
838#endif
839
840            char timecode_s[64];
841            strftime(timecode_s,sizeof(timecode_s),"%Y-%m-%d %H:%M:%S",&t);
842
843            fprintf(subs,"%u\n%s --> %s\n%s\n\n",++subs_num,start.c_str(),end.c_str(),timecode_s);
844
845            timecode+=1;
846        }
847    }
848
849
850    base_pts+=length;
851
852#ifndef OLD_TIMECODES
853    // align
854    if(base_pts%90)
855        base_pts=base_pts/90*90+90;
856#endif
857
858    return 0;
859}
860
861void ts::demuxer::write_timecodes(FILE* fp,u_int64_t first_pts,u_int64_t last_pts,u_int32_t frame_num,u_int32_t frame_len)
862{
863    u_int64_t len=last_pts-first_pts;
864
865    double c=(double)len/(double)frame_num;
866
867    double m=0;
868    u_int32_t n=0;
869
870    for(int i=0;i<frame_num;i++)
871    {
872        fprintf(fp,"%llu\n",(first_pts+n)/90);
873
874        m+=c;
875        n+=c;
876
877        if(m-n>=1)
878            n+=1;
879    }
880}
881
882#ifndef OLD_TIMECODES
883// for audio
884void ts::demuxer::write_timecodes2(FILE* fp,u_int64_t first_pts,u_int64_t last_pts,u_int32_t frame_num,u_int32_t frame_len)
885{
886    u_int64_t len=last_pts-first_pts;
887
888    u_int64_t len2=frame_num*frame_len;
889
890    if(len2>len || frame_len%90)
891        write_timecodes(fp,first_pts,last_pts,frame_num,frame_len);
892    else
893    {
894        u_int32_t frame_len_ms=frame_len/90;
895        u_int32_t timecode_ms=base_pts/90;
896
897        for(u_int32_t i=0;i<frame_num;i++)
898        {
899            fprintf(fp,"%u\n",timecode_ms);
900            timecode_ms+=frame_len_ms;
901        }
902    }
903}
904#endif
Note: See TracBrowser for help on using the repository browser.