dvbstream-20090621.orig/0000755000175000017500000000000011424666467013373 5ustar markmarkdvbstream-20090621.orig/ts_filter.c0000644000175000017500000000312510000237350015501 0ustar markmark/* A simple filter (stdin -> stdout) to extract multiple streams from a multiplexed TS. Specify the PID on the command-line Updated 29th January 2003 - Added some error checking and reporting. */ #include #include #include int main(int argc, char **argv) { int pid,n; int filters[8192]; unsigned int i=0; unsigned int j=0; unsigned char buf[188]; unsigned char my_cc[8192]; int errors=0; for (i=0;i<8192;i++) { filters[i]=0; my_cc[i]=0xff;} for (i=1;i #include #include #include #include #include #include #include #include /* MPEG-2 TS RTP stack */ #define DEBUG 1 #include "rtp.h" /* Payload types (from RFC 1890): PT encoding audio/video clock rate channels name (A/V) (Hz) (audio) _______________________________________________________________ 0 PCMU A 8000 1 1 1016 A 8000 1 2 G721 A 8000 1 3 GSM A 8000 1 4 unassigned A 8000 1 5 DVI4 A 8000 1 6 DVI4 A 16000 1 7 LPC A 8000 1 8 PCMA A 8000 1 9 G722 A 8000 1 10 L16 A 44100 2 11 L16 A 44100 1 12 unassigned A 13 unassigned A 14 MPA A 90000 (see text) 15 G728 A 8000 1 16--23 unassigned A 24 unassigned V 25 CelB V 90000 26 JPEG V 90000 27 unassigned V 28 nv V 90000 29 unassigned V 30 unassigned V 31 H261 V 90000 32 MPV V 90000 33 MP2T AV 90000 34--71 unassigned ? 72--76 reserved N/A N/A N/A 77--95 unassigned ? 96--127 dynamic ? */ void initrtp(struct rtpheader *foo,int pt, int type) { /* fill in the MPEG-2 TS deefaults */ /* Note: MPEG-2 TS defines a timestamping base frequency of 90000 Hz. */ foo->b.v=2; foo->b.p=0; foo->b.x=0; foo->b.cc=0; foo->b.m=0; foo->b.pt=pt; foo->b.sequence=rand() & 65535; foo->timestamp=rand(); foo->ssrc=rand(); foo->type = type; } /* Send a single RTP packet, converting the RTP header to network byte order. */ int sendrtp(int fd, struct sockaddr_in *sSockAddr, struct rtpheader *foo, char *data, int len) { char *buf=(char*)alloca(len+sizeof(struct rtpheader)); int *cast=(int *)foo; int *outcast=(int *)buf; outcast[0]=htonl(cast[0]); outcast[1]=htonl(cast[1]); memmove(outcast+2,data,len); fprintf(stderr,"v=%x %x\n",foo->b.v,buf[0]); return sendto(fd,buf,len+3,0,(struct sockaddr *)sSockAddr,sizeof(*sSockAddr)); } int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData) { static char buf[1600]; unsigned int intP; char* charP = (char*) &intP; int headerSize; int lengthPacket; lengthPacket=recv(fd,buf,1590,0); if (lengthPacket==0) exit(1); if (lengthPacket<0) { fprintf(stderr,"socket read error\n"); exit(2); } if (lengthPacket<12) { fprintf(stderr,"packet too small (%d) to be an rtp frame (>12bytes)\n",lengthPacket); exit(3); } rh->b.v = (unsigned int) ((buf[0]>>6)&0x03); rh->b.p = (unsigned int) ((buf[0]>>5)&0x01); rh->b.x = (unsigned int) ((buf[0]>>4)&0x01); rh->b.cc = (unsigned int) ((buf[0]>>0)&0x0f); rh->b.m = (unsigned int) ((buf[1]>>7)&0x01); rh->b.pt = (unsigned int) ((buf[1]>>0)&0x7f); intP = 0; memcpy(charP+2,&buf[2],2); rh->b.sequence = ntohl(intP); intP = 0; memcpy(charP,&buf[4],4); rh->timestamp = ntohl(intP); headerSize = 12 + 4*rh->b.cc; /* in bytes */ *lengthData = lengthPacket - headerSize; *data = (char*) buf + headerSize; // fprintf(stderr,"Reading rtp: v=%x p=%x x=%x cc=%x m=%x pt=%x seq=%x ts=%x lgth=%d\n",rh->b.v,rh->b.p,rh->b.x,rh->b.cc,rh->b.m,rh->b.pt,rh->b.sequence,rh->timestamp,lengthPacket); return(0); } /* Send a single RTP packet, converting the RTP header to network byte order. */ int sendrtp2(int fd, struct sockaddr_in *sSockAddr, struct rtpheader *foo, char *data, int len) { char *buf; unsigned int intP; char* charP = (char*) &intP; int headerSize; if(foo->type == RTP) { buf=(char*)alloca(len+72); buf[0] = 0x00; buf[0] |= ((((char) foo->b.v)<<6)&0xc0); buf[0] |= ((((char) foo->b.p)<<5)&0x20); buf[0] |= ((((char) foo->b.x)<<4)&0x10); buf[0] |= ((((char) foo->b.cc)<<0)&0x0f); buf[1] = 0x00; buf[1] |= ((((char) foo->b.m)<<7)&0x80); buf[1] |= ((((char) foo->b.pt)<<0)&0x7f); intP = htonl(foo->b.sequence); memcpy(&buf[2],charP+2,2); intP = htonl(foo->timestamp); memcpy(&buf[4],&intP,4); /* SSRC: not implemented */ buf[8] = 0x0f; buf[9] = 0x0f; buf[10] = 0x0f; buf[11] = 0x0f; headerSize = 12 + 4*foo->b.cc; /* in bytes */ memcpy(buf+headerSize,data,len); // fprintf(stderr,"Sending rtp: v=%x p=%x x=%x cc=%x m=%x pt=%x seq=%x ts=%x lgth=%d\n",foo->b.v,foo->b.p,foo->b.x,foo->b.cc,foo->b.m,foo->b.pt,foo->b.sequence,foo->timestamp,len+headerSize); foo->b.sequence++; } else { //UDP buf = data; headerSize = 0; } return sendto(fd,buf,len+headerSize,0,(struct sockaddr *)sSockAddr,sizeof(*sSockAddr)); } int getrtp(int fd, struct rtpheader *rh, char** data, int* lengthData) { static char buf[1600]; int headerSize; int lengthPacket; lengthPacket=recv(fd,buf,1590,0); headerSize = 3; *lengthData = lengthPacket - headerSize; *data = (char*) buf + headerSize; fprintf(stderr,"[%d] %02x %x\n",lengthPacket,buf[8],buf[0]); return(0); } /* create a sender socket. */ int makesocket(char *szAddr,unsigned short port,int TTL,struct sockaddr_in *sSockAddr) { int iRet, iLoop = 1; struct sockaddr_in sin; char cTtl = (char)TTL; char cLoop=0; int iSocket = socket( AF_INET, SOCK_DGRAM, 0 ); if (iSocket < 0) { fprintf(stderr,"socket() failed.\n"); exit(1); } sSockAddr->sin_family = sin.sin_family = AF_INET; sSockAddr->sin_port = sin.sin_port = htons(port); sSockAddr->sin_addr.s_addr = inet_addr(szAddr); iRet = setsockopt(iSocket, SOL_SOCKET, SO_REUSEADDR, &iLoop, sizeof(int)); if (iRet < 0) { fprintf(stderr,"setsockopt SO_REUSEADDR failed\n"); exit(1); } iRet = setsockopt(iSocket, IPPROTO_IP, IP_MULTICAST_TTL, &cTtl, sizeof(char)); if (iRet < 0) { fprintf(stderr,"setsockopt IP_MULTICAST_TTL failed. multicast in kernel?\n"); exit(1); } cLoop = 1; /* !? */ iRet = setsockopt(iSocket, IPPROTO_IP, IP_MULTICAST_LOOP, &cLoop, sizeof(char)); if (iRet < 0) { fprintf(stderr,"setsockopt IP_MULTICAST_LOOP failed. multicast in kernel?\n"); exit(1); } return iSocket; } /* create a receiver socket, i.e. join the multicast group. */ int makeclientsocket(char *szAddr,unsigned short port,int TTL,struct sockaddr_in *sSockAddr) { int socket=makesocket(szAddr,port,TTL,sSockAddr); struct ip_mreq blub; struct sockaddr_in sin; unsigned int tempaddr; sin.sin_family=AF_INET; sin.sin_port=htons(port); sin.sin_addr.s_addr=inet_addr(szAddr); if (bind(socket,(struct sockaddr *)&sin,sizeof(sin))) { perror("bind failed"); exit(1); } tempaddr=inet_addr(szAddr); if ((ntohl(tempaddr) >> 28) == 0xe) { blub.imr_multiaddr.s_addr = inet_addr(szAddr); blub.imr_interface.s_addr = 0; if (setsockopt(socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,&blub,sizeof(blub))) { perror("setsockopt IP_ADD_MEMBERSHIP failed (multicast kernel?)"); exit(1); } } return socket; } dvbstream-20090621.orig/dumprtp.c0000644000175000017500000000404407741324225015222 0ustar markmark/* * dumprtp.c: get an rtp unicast/multicast/broacast stream and outputs it * Author: David Podeur for Convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at david@convergence.de, */ #include #include #include #include #include #include #include #include "rtp.h" void dumprtp(int socket) { char* buf; struct rtpheader rh; int lengthData; unsigned short seq=0; int flag=0; while(1) { getrtp2(socket,&rh, &buf,&lengthData); if (flag==0) { seq=rh.b.sequence; flag=1; } if (seq!=rh.b.sequence) { fprintf(stderr,"rtptsaudio: NETWORK CONGESTION - expected %d, received %d\n",seq,rh.b.sequence); seq=rh.b.sequence; } seq++; write(1,buf,lengthData); } } int main(int argc, char *argv[]) { struct sockaddr_in si; int socketIn; char *ip; int port; fprintf(stderr,"Rtp dump\n"); if (argc == 1) { ip = "224.0.1.2"; port = 5004; } else if (argc == 3) { ip = argv[1]; port = atoi(argv[2]); } else { fprintf(stderr,"Usage %s ip port\n",argv[0]); exit(1); } fprintf(stderr,"Using %s:%d\n",ip,port); socketIn = makeclientsocket(ip,port,2,&si); dumprtp(socketIn); close(socketIn); return(0); } dvbstream-20090621.orig/COPYING0000644000175000017500000004307607470507541014431 0ustar markmark GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. dvbstream-20090621.orig/mpegtools/0000755000175000017500000000000011424666470015376 5ustar markmarkdvbstream-20090621.orig/mpegtools/ctools.c0000644000175000017500000013507707470507557017070 0ustar markmark/* * mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at marcus@convergence.de, * the project's page is at http://linuxtv.org/dvb/ */ #include "ctools.h" #define MAX_SEARCH 1024 * 1024 /* PES */ void init_pes(pes_packet *p){ p->stream_id = 0; p->llength[0] = 0; p->llength[1] = 0; p->length = 0; p->flags1 = 0x80; p->flags2 = 0; p->pes_hlength = 0; p->trick = 0; p->add_cpy = 0; p->priv_flags = 0; p->pack_field_length = 0; p->pack_header = (u8 *) NULL; p->pck_sqnc_cntr = 0; p->org_stuff_length = 0; p->pes_ext_lngth = 0; p->pes_ext = (u8 *) NULL; p->pes_pckt_data = (u8 *) NULL; p->padding = 0; p->mpeg = 2; // DEFAULT MPEG2 p->mpeg1_pad = 0; p->mpeg1_headr = NULL; p->stuffing = 0; } void kill_pes(pes_packet *p){ if (p->pack_header) free(p->pack_header); if (p->pes_ext) free(p->pes_ext); if (p->pes_pckt_data) free(p->pes_pckt_data); if (p->mpeg1_headr) free(p->mpeg1_headr); init_pes(p); } void setlength_pes(pes_packet *p){ short *ll; ll = (short *) p->llength; p->length = ntohs(*ll); } static void setl_pes(pes_packet *p){ setlength_pes(p); if (p->length) p->pes_pckt_data = (u8 *)malloc(p->length); } void nlength_pes(pes_packet *p){ if (p->length <= 0xFFFF){ short *ll = (short *) p->llength; short l = p->length; *ll = htons(l); } else { p->llength[0] =0x00; p->llength[1] =0x00; } } static void nl_pes(pes_packet *p) { nlength_pes(p); p->pes_pckt_data = (u8 *) malloc(p->length); } void pts2pts(u8 *av_pts, u8 *pts) { av_pts[0] = ((pts[0] & 0x06) << 5) | ((pts[1] & 0xFC) >> 2); av_pts[1] = ((pts[1] & 0x03) << 6) | ((pts[2] & 0xFC) >> 2); av_pts[2] = ((pts[2] & 0x02) << 6) | ((pts[3] & 0xFE) >> 1); av_pts[3] = ((pts[3] & 0x01) << 7) | ((pts[4] & 0xFE) >> 1); } int cwrite_pes(u8 *buf, pes_packet *p, long length){ int count,i; u8 dummy; int more = 0; u8 headr[3] = { 0x00, 0x00 , 0x01}; if (length < p->length+p->pes_hlength){ fprintf(stderr,"Wrong buffer size in cwrite_pes\n"); exit(1); } memcpy(buf,headr,3); count = 3; buf[count] = p->stream_id; count++; switch ( p->stream_id ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : buf[count] = p->llength[0]; count++; buf[count] = p->llength[1]; count++; memcpy(buf+count,p->pes_pckt_data,p->length); count += p->length; break; case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: buf[count] = p->llength[0]; count++; buf[count] = p->llength[1]; count++; more = 1; break; } if ( more ) { if ( p->mpeg == 2 ){ memcpy(buf+count,&p->flags1,1); count++; memcpy(buf+count,&p->flags2,1); count++; memcpy(buf+count,&p->pes_hlength,1); count++; if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ memcpy(buf+count,p->pts,5); count += 5; } else if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ memcpy(buf+count,p->pts,5); count += 5; memcpy(buf+count,p->dts,5); count += 5; } if (p->flags2 & ESCR_FLAG){ memcpy(buf+count,p->escr,6); count += 6; } if (p->flags2 & ES_RATE_FLAG){ memcpy(buf+count,p->es_rate,3); count += 3; } if (p->flags2 & DSM_TRICK_FLAG){ memcpy(buf+count,&p->trick,1); count++; } if (p->flags2 & ADD_CPY_FLAG){ memcpy(buf+count,&p->add_cpy,1); count++; } if (p->flags2 & PES_CRC_FLAG){ memcpy(buf+count,p->prev_pes_crc,2); count += 2; } if (p->flags2 & PES_EXT_FLAG){ memcpy(buf+count,&p->priv_flags,1); count++; if (p->priv_flags & PRIVATE_DATA){ memcpy(buf+count,p->pes_priv_data,16); count += 16; } if (p->priv_flags & HEADER_FIELD){ memcpy(buf+count,&p->pack_field_length, 1); count++; memcpy(buf+count,p->pack_header, p->pack_field_length); count += p->pack_field_length; } if ( p->priv_flags & PACK_SEQ_CTR){ memcpy(buf+count,&p->pck_sqnc_cntr,1); count++; memcpy(buf+count,&p->org_stuff_length, 1); count++; } if ( p->priv_flags & P_STD_BUFFER){ memcpy(buf+count,p->p_std,2); count += 2; } if ( p->priv_flags & PES_EXT_FLAG2){ memcpy(buf+count,&p->pes_ext_lngth,1); count++; memcpy(buf+count,p->pes_ext, p->pes_ext_lngth); count += p->pes_ext_lngth; } } dummy = 0xFF; for (i=0;istuffing;i++) { memcpy(buf+count,&dummy,1); count++; } } else { if (p->mpeg1_pad){ memcpy(buf+count,p->mpeg1_headr,p->mpeg1_pad); count += p->mpeg1_pad; } if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ memcpy(buf+count,p->pts,5); count += 5; } else if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ memcpy(buf+count,p->pts,5); count += 5; memcpy(buf+count,p->dts,5); count += 5; } } memcpy(buf+count,p->pes_pckt_data,p->length); count += p->length; } return count; } void write_pes(int fd, pes_packet *p){ long length; u8 *buf; int l = p->length+p->pes_hlength; buf = (u8 *) malloc(l); length = cwrite_pes(buf,p,l); write(fd,buf,length); free(buf); } static unsigned int find_length(int f){ uint64_t p = 0; uint64_t start = 0; uint64_t q = 0; int found = 0; u8 sync4[4]; int neof = 1; start = lseek(f,0,SEEK_CUR); start -=2; lseek(f,start,SEEK_SET); while ( neof > 0 && !found ){ p = lseek(f,0,SEEK_CUR); neof = read(f,&sync4,4); if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { switch ( sync4[3] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: found = 1; break; default: q = lseek(f,0,SEEK_CUR); break; } } } q = lseek(f,0,SEEK_CUR); lseek(f,start+2,SEEK_SET); if (found) return (unsigned int)(q-start)-4-2; else return (unsigned int)(q-start-2); } void cread_pes(char *buf, pes_packet *p){ u8 count, dummy, check; int i; uint64_t po = 0; int c=0; switch ( p->stream_id ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : memcpy(p->pes_pckt_data,buf+c,p->length); return; break; case PADDING_STREAM : p->padding = p->length; memcpy(p->pes_pckt_data,buf+c,p->length); return; break; case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: break; default: return; break; } po = c; memcpy(&p->flags1,buf+c,1); c++; if ( (p->flags1 & 0xC0) == 0x80 ) p->mpeg = 2; else p->mpeg = 1; if ( p->mpeg == 2 ){ memcpy(&p->flags2,buf+c,1); c++; memcpy(&p->pes_hlength,buf+c,1); c++; p->length -=p->pes_hlength+3; count = p->pes_hlength; if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ memcpy(p->pts,buf+c,5); c += 5; count -=5; } else if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ memcpy(p->pts,buf+c,5); c += 5; memcpy(p->dts,buf+c,5); c += 5; count -= 10; } if (p->flags2 & ESCR_FLAG){ memcpy(p->escr,buf+c,6); c += 6; count -= 6; } if (p->flags2 & ES_RATE_FLAG){ memcpy(p->es_rate,buf+c,3); c += 6; count -= 6; } if (p->flags2 & DSM_TRICK_FLAG){ memcpy(&p->trick,buf+c,1); c += 6; count -= 1; } if (p->flags2 & ADD_CPY_FLAG){ memcpy(&p->add_cpy,buf+c,1); c++; count -= 1; } if (p->flags2 & PES_CRC_FLAG){ memcpy(p->prev_pes_crc,buf+c,2); c += 2; count -= 2; } if (p->flags2 & PES_EXT_FLAG){ memcpy(&p->priv_flags,buf+c,1); c++; count -= 1; if (p->priv_flags & PRIVATE_DATA){ memcpy(p->pes_priv_data,buf+c,16); c += 16; count -= 16; } if (p->priv_flags & HEADER_FIELD){ memcpy(&p->pack_field_length,buf+c,1); c++; p->pack_header = (u8 *) malloc(p->pack_field_length); memcpy(p->pack_header,buf+c, p->pack_field_length); c += p->pack_field_length; count -= 1+p->pack_field_length; } if ( p->priv_flags & PACK_SEQ_CTR){ memcpy(&p->pck_sqnc_cntr,buf+c,1); c++; memcpy(&p->org_stuff_length,buf+c,1); c++; count -= 2; } if ( p->priv_flags & P_STD_BUFFER){ memcpy(p->p_std,buf+c,2); c += 2; count -= 2; } if ( p->priv_flags & PES_EXT_FLAG2){ memcpy(&p->pes_ext_lngth,buf+c,1); c++; p->pes_ext = (u8 *) malloc(p->pes_ext_lngth); memcpy(p->pes_ext,buf+c, p->pes_ext_lngth); c += p->pes_ext_lngth; count -= 1+p->pes_ext_lngth; } } p->stuffing = count; for(i = 0; i< count ;i++){ memcpy(&dummy,buf+c,1); c++; } } else { p->mpeg1_pad = 1; check = p->flags1; while (check == 0xFF){ memcpy(&check,buf+c,1); c++; p->mpeg1_pad++; } if ( (check & 0xC0) == 0x40){ memcpy(&check,buf+c,1); c++; p->mpeg1_pad++; memcpy(&check,buf+c,1); c++; p->mpeg1_pad++; } p->flags2 = 0; p->length -= p->mpeg1_pad; c = po; if ( (check & 0x30)){ p->length ++; p->mpeg1_pad --; if (check == p->flags1){ p->pes_hlength = 0; } else { p->mpeg1_headr = (u8 *) malloc(p->mpeg1_pad); p->pes_hlength = p->mpeg1_pad; memcpy(p->mpeg1_headr,buf+c, p->mpeg1_pad); c += p->mpeg1_pad; } p->flags2 = (check & 0xF0) << 2; if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ memcpy(p->pts,buf+c,5); c += 5; p->length -= 5; p->pes_hlength += 5; } else if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ memcpy(p->pts,buf+c,5); c += 5; memcpy(p->dts,buf+c,5); c += 5; p->length -= 10; p->pes_hlength += 10; } } else { p->mpeg1_headr = (u8 *) malloc(p->mpeg1_pad); p->pes_hlength = p->mpeg1_pad; memcpy(p->mpeg1_headr,buf+c, p->mpeg1_pad); c += p->mpeg1_pad; } } memcpy(p->pes_pckt_data,buf+c,p->length); } int read_pes(int f, pes_packet *p){ u8 sync4[4]; int found=0; uint64_t po = 0; int neof = 1; u8 *buf; while (neof > 0 && !found) { po = lseek(f,0,SEEK_CUR); if (po < 0) return -1; if ((neof = read(f,&sync4,4)) < 4) return -1; if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { p->stream_id = sync4[3]; switch ( sync4[3] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: if((neof = read(f,p->llength,2)) < 2) return -1; setl_pes(p); if (!p->length){ p->length = find_length(f); nl_pes(p); } found = 1; break; default: if (lseek(f,po+1,SEEK_SET) < po+1) return -1; break; } } else if(lseek(f,po+1,SEEK_SET) < po+1) return -1; } if (!found || !p->length) return 0; if (p->length >0){ buf = (u8 *) malloc(p->length); if((neof = read(f,buf,p->length))< p->length) return -1; cread_pes((char *)buf,p); free(buf); } else return 0; return neof; } /* Transport Stream */ void init_ts(ts_packet *p){ p->pid[0] = 0; p->pid[1] = 0; p->flags = 0; p->count = 0; p->adapt_length = 0; p->adapt_flags = 0; p->splice_count = 0; p->priv_dat_len = 0; p->priv_dat = NULL; p->adapt_ext_len = 0; p->adapt_eflags = 0; p->rest = 0; p->stuffing = 0; } void kill_ts(ts_packet *p){ if (p->priv_dat) free(p->priv_dat); init_ts(p); } unsigned short pid_ts(ts_packet *p) { return get_pid(p->pid); } int cwrite_ts(u8 *buf, ts_packet *p, long length){ long count,i; u8 sync,dummy; sync = 0x47; memcpy(buf,&sync,1); count = 1; memcpy(buf+count,p->pid,2); count += 2; memcpy(buf+count,&p->flags,1); count++; if (! (p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ memcpy(buf+count,p->data,184); count += 184; } else { memcpy(buf+count,&p->adapt_length,1); count++; memcpy(buf+count,&p->adapt_flags,1); count++; if ( p->adapt_flags & PCR_FLAG ){ memcpy(buf+count, p->pcr,6); count += 6; } if ( p->adapt_flags & OPCR_FLAG ){ memcpy(buf+count, p->opcr,6); count += 6; } if ( p->adapt_flags & SPLICE_FLAG ){ memcpy(buf+count, &p->splice_count,1); count++; } if( p->adapt_flags & TRANS_PRIV){ memcpy(buf+count,&p->priv_dat_len,1); count++; memcpy(buf+count,p->priv_dat,p->priv_dat_len); count += p->priv_dat_len; } if( p->adapt_flags & ADAP_EXT_FLAG){ memcpy(buf+count,&p->adapt_ext_len,1); count++; memcpy(buf+count,&p->adapt_eflags,1); count++; if( p->adapt_eflags & LTW_FLAG){ memcpy(buf+count,p->ltw,2); count += 2; } if( p->adapt_eflags & PIECE_RATE){ memcpy(buf+count,p->piece_rate,3); count += 3; } if( p->adapt_eflags & SEAM_SPLICE){ memcpy(buf+count,p->dts,5); count += 5; } } dummy = 0xFF; for(i=0; i < p->stuffing ; i++){ memcpy(buf+count,&dummy,1); count++; } if (p->flags & PAYLOAD){ memcpy(buf+count,p->data,p->rest); count += p->rest; } } return count; } void write_ts(int fd, ts_packet *p){ long length; u8 buf[TS_SIZE]; length = cwrite_ts(buf,p,TS_SIZE); write(fd,buf,length); } int read_ts (int f, ts_packet *p){ u8 sync; int found=0; uint64_t po,q; int neof = 1; sync=0; while (neof > 0 && !found) { neof = read(f,&sync,1); if (sync == 0x47) found = 1; } neof = read(f,p->pid,2); neof = read(f,&p->flags,1); p->count = p->flags & COUNT_MASK; if (!(p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ //no adapt. field only payload neof = read(f,p->data,184); p->rest = 184; return neof; } if ( p->flags & ADAPT_FIELD ) { // adaption field neof = read(f,&p->adapt_length,1); po = lseek(f,0,SEEK_CUR); neof = read(f,&p->adapt_flags,1); if ( p->adapt_flags & PCR_FLAG ) neof = read(f, p->pcr,6); if ( p->adapt_flags & OPCR_FLAG ) neof = read(f, p->opcr,6); if ( p->adapt_flags & SPLICE_FLAG ) neof = read(f, &p->splice_count,1); if( p->adapt_flags & TRANS_PRIV){ neof = read(f,&p->priv_dat_len,1); p->priv_dat = (u8 *) malloc(p->priv_dat_len); neof = read(f,p->priv_dat,p->priv_dat_len); } if( p->adapt_flags & ADAP_EXT_FLAG){ neof = read(f,&p->adapt_ext_len,1); neof = read(f,&p->adapt_eflags,1); if( p->adapt_eflags & LTW_FLAG) neof = read(f,p->ltw,2); if( p->adapt_eflags & PIECE_RATE) neof = read(f,p->piece_rate,3); if( p->adapt_eflags & SEAM_SPLICE) neof = read(f,p->dts,5); } q = lseek(f,0,SEEK_CUR); p->stuffing = p->adapt_length -(q-po); p->rest = 183-p->adapt_length; lseek(f,q+p->stuffing,SEEK_SET); if (p->flags & PAYLOAD) // payload neof = read(f,p->data,p->rest); else lseek(f,q+p->rest,SEEK_SET); } return neof; } void cread_ts (char *buf, ts_packet *p, long length){ u8 sync; int found=0; uint64_t po,q; long count=0; sync=0; while (count < length && !found) { sync=buf[count]; count++; if (sync == 0x47) found = 1; } memcpy(p->pid,buf+count,2); count += 2; p->flags = buf[count]; count++; p->count = p->flags & COUNT_MASK; if (!(p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ //no adapt. field only payload memcpy(p->data,buf+count,184); p->rest = 184; return; } if ( p->flags & ADAPT_FIELD ) { // adaption field p->adapt_length = buf[count]; count++; po = count; memcpy(&p->adapt_flags,buf+count,1); count++; if ( p->adapt_flags & PCR_FLAG ){ memcpy( p->pcr,buf+count,6); count += 6; } if ( p->adapt_flags & OPCR_FLAG ){ memcpy( p->opcr,buf+count,6); count += 6; } if ( p->adapt_flags & SPLICE_FLAG ){ memcpy( &p->splice_count,buf+count,1); count++; } if( p->adapt_flags & TRANS_PRIV){ memcpy(&p->priv_dat_len,buf+count,1); count++; p->priv_dat = (u8 *) malloc(p->priv_dat_len); memcpy(p->priv_dat,buf+count,p->priv_dat_len); count += p->priv_dat_len; } if( p->adapt_flags & ADAP_EXT_FLAG){ memcpy(&p->adapt_ext_len,buf+count,1); count++; memcpy(&p->adapt_eflags,buf+count,1); count++; if( p->adapt_eflags & LTW_FLAG){ memcpy(p->ltw,buf+count,2); count += 2; } if( p->adapt_eflags & PIECE_RATE){ memcpy(p->piece_rate,buf+count,3); count += 3; } if( p->adapt_eflags & SEAM_SPLICE){ memcpy(p->dts,buf+count,5); count += 5; } } q = count; p->stuffing = p->adapt_length -(q-po); p->rest = 183-p->adapt_length; count = q+p->stuffing; if (p->flags & PAYLOAD){ // payload memcpy(p->data,buf+count,p->rest); count += p->rest; } else count = q+p->rest; } } /* Program Stream */ void init_ps(ps_packet *p) { p->stuff_length=0xF8; p->data = NULL; p->sheader_length = 0; p->audio_bound = 0; p->video_bound = 0; p->npes = 0; p->mpeg = 2; } void kill_ps(ps_packet *p) { if (p->data) free(p->data); init_ps(p); } void setlength_ps(ps_packet *p) { short *ll; ll = (short *) p->sheader_llength; if (p->mpeg == 2) p->sheader_length = ntohs(*ll) - 6; else p->sheader_length = ntohs(*ll); } static void setl_ps(ps_packet *p) { setlength_ps(p); p->data = (u8 *) malloc(p->sheader_length); } int mux_ps(ps_packet *p) { u32 mux = 0; u8 *i = (u8 *)&mux; i[1] = p->mux_rate[0]; i[2] = p->mux_rate[1]; i[3] = p->mux_rate[2]; mux = ntohl(mux); mux = (mux >>2); return mux; } int rate_ps(ps_packet *p) { u32 rate=0; u8 *i= (u8 *) &rate; i[1] = p->rate_bound[0] & 0x7F; i[2] = p->rate_bound[1]; i[3] = p->rate_bound[2]; rate = ntohl(rate); rate = (rate >> 1); return rate; } u32 scr_base_ps(ps_packet *p) // only 32 bit!! { u32 base = 0; u8 *buf = (u8 *)&base; buf[0] |= (long int)((p->scr[0] & 0x18) << 3); buf[0] |= (long int)((p->scr[0] & 0x03) << 4); buf[0] |= (long int)((p->scr[1] & 0xF0) >> 4); buf[1] |= (long int)((p->scr[1] & 0x0F) << 4); buf[1] |= (long int)((p->scr[2] & 0xF0) >> 4); buf[2] |= (long int)((p->scr[2] & 0x08) << 4); buf[2] |= (long int)((p->scr[2] & 0x03) << 5); buf[2] |= (long int)((p->scr[3] & 0xF8) >> 3); buf[3] |= (long int)((p->scr[3] & 0x07) << 5); buf[3] |= (long int)((p->scr[4] & 0xF8) >> 3); base = ntohl(base); return base; } u16 scr_ext_ps(ps_packet *p) { short ext = 0; ext = (short)(p->scr[5] >> 1); ext += (short) (p->scr[4] & 0x03) * 128; return ext; } int cwrite_ps(u8 *buf, ps_packet *p, long length) { long count,i; u8 headr1[4] = {0x00, 0x00, 0x01, 0xBA }; u8 headr2[4] = {0x00, 0x00, 0x01, 0xBB }; u8 buffy = 0xFF; memcpy(buf,headr1,4); count = 4; if (p->mpeg == 2){ memcpy(buf+count,p->scr,6); count += 6; memcpy(buf+count,p->mux_rate,3); count += 3; memcpy(buf+count,&p->stuff_length,1); count++; for(i=0; i< (p->stuff_length & 3); i++){ memcpy(buf+count,&buffy,1); count++; } } else { memcpy(buf+count,p->scr,5); count += 5; memcpy(buf+count,p->mux_rate,3); count += 3; } if (p->sheader_length){ memcpy(buf+count,headr2,4); count += 4; memcpy(buf+count,p->sheader_llength,2); count += 2; if ( p->mpeg == 2){ memcpy(buf+count,p->rate_bound,3); count += 3; memcpy(buf+count,&p->audio_bound,1); count++; memcpy(buf+count,&p->video_bound,1); count++; memcpy(buf+count,&p->reserved,1); count++; } memcpy(buf+count,p->data,p->sheader_length); count += p->sheader_length; } return count; } void write_ps(int fd, ps_packet *p){ long length; u8 buf[PS_MAX]; length = cwrite_ps(buf,p,PS_MAX); write(fd,buf,length); } int read_ps (int f, ps_packet *p){ u8 headr[4]; pes_packet pes; int i,done; int found=0; uint64_t po = 0; uint64_t q = 0; long count = 0; int neof = 1; po = lseek(f,0,SEEK_CUR); while (neof > 0 && !found && count < MAX_SEARCH) { neof = read(f,&headr,4); if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01){ if ( headr[3] == 0xBA ) found = 1; else if ( headr[3] == 0xB9 ) break; else lseek(f,po+1,SEEK_SET); } count++; } if (found){ neof = read(f,p->scr,6); if (p->scr[0] & 0x40) p->mpeg = 2; else p->mpeg = 1; if (p->mpeg == 2){ neof = read(f,p->mux_rate,3); neof = read(f,&p->stuff_length,1); po = lseek(f,0,SEEK_CUR); lseek(f,po+(p->stuff_length & 3),SEEK_SET); } else { p->mux_rate[0] = p->scr[5]; //mpeg1 scr is only 5 bytes neof = read(f,p->mux_rate+1,2); } po = lseek(f,0,SEEK_CUR); neof = read(f,headr,4); if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] == 0xBB ) { neof = read(f,p->sheader_llength,2); setl_ps(p); if (p->mpeg == 2){ neof = read(f,p->rate_bound,3); neof = read(f,&p->audio_bound,1); neof = read(f,&p->video_bound,1); neof = read(f,&p->reserved,1); } neof = read(f,p->data,p->sheader_length); } else { lseek(f,po,SEEK_SET); p->sheader_length = 0; } i = 0; done = 0; q = lseek(f,0,SEEK_CUR); do { po = lseek(f,0,SEEK_CUR); neof = read(f,headr,4); lseek(f,po,SEEK_SET); if ( headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] != 0xBA){ init_pes(&pes); neof = read_pes(f,&pes); i++; } else done = 1; kill_pes(&pes); } while ( neof > 0 && !done); p->npes = i; lseek(f,q,SEEK_SET); } return neof; } void cread_ps (char *buf, ps_packet *p, long length){ u8 *headr; pes_packet pes; int i,done; int found=0; uint64_t po = 0; uint64_t q = 0; long count = 0; long c = 0; po = c; while ( count < length && !found && count < MAX_SEARCH) { headr = (u8 *)buf+c; c += 4; if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01){ if ( headr[3] == 0xBA ) found = 1; else if ( headr[3] == 0xB9 ) break; else c = po+1; } count++; } if (found){ memcpy(p->scr,buf+c,6); c += 6; if (p->scr[0] & 0x40) p->mpeg = 2; else p->mpeg = 1; if (p->mpeg == 2){ memcpy(p->mux_rate,buf+c,3); c += 3; memcpy(&p->stuff_length,buf+c,1); c++; po = c; c = po+(p->stuff_length & 3); } else { p->mux_rate[0] = p->scr[5]; //mpeg1 scr is only 5 bytes memcpy(p->mux_rate+1,buf+c,2); c += 2; } po = c; headr = (u8 *)buf+c; c += 4; if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] == 0xBB ) { memcpy(p->sheader_llength,buf+c,2); c += 2; setl_ps(p); if (p->mpeg == 2){ memcpy(p->rate_bound,buf+c,3); c += 3; memcpy(&p->audio_bound,buf+c,1); c++; memcpy(&p->video_bound,buf+c,1); c++; memcpy(&p->reserved,buf+c,1); c++; } memcpy(p->data,buf+c,p->sheader_length); c += p->sheader_length; } else { c = po; p->sheader_length = 0; } i = 0; done = 0; q = c; do { headr = (u8 *)buf+c; if ( headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] != 0xBA){ init_pes(&pes); // cread_pes(buf+c,&pes); i++; } else done = 1; kill_pes(&pes); } while (c < length && !done); p->npes = i; c = q; } } /* conversion */ void init_trans(trans *p) { int i; p->found = 0; p->pes = 0; p->is_full = 0; p->pes_start = 0; p->pes_started = 0; p->set = 0; for (i = 0; i < MASKL*MAXFILT ; i++){ p->mask[i] = 0; p->filt[i] = 0; } for (i = 0; i < MAXFILT ; i++){ p->sec[i].found = 0; p->sec[i].length = 0; } } int set_trans_filt(trans *p, int filtn, u16 pid, u8 *mask, u8 *filt, int pes) { int i; int off; if ( filtn > MAXFILT-1 || filtn<0 ) return -1; p->pid[filtn] = pid; if (pes) p->pes |= (tflags)(1 << filtn); else { off = MASKL*filtn; p->pes &= ~((tflags) (1 << filtn) ); for (i = 0; i < MASKL ; i++){ p->mask[off+i] = mask[i]; p->filt[off+i] = filt[i]; } } p->set |= (tflags) (1 << filtn); return 0; } void clear_trans_filt(trans *p,int filtn) { int i; p->set &= ~((tflags) (1 << filtn) ); p->pes &= ~((tflags) (1 << filtn) ); p->is_full &= ~((tflags) (1 << filtn) ); p->pes_start &= ~((tflags) (1 << filtn) ); p->pes_started &= ~((tflags) (1 << filtn) ); for (i = MASKL*filtn; i < MASKL*(filtn+1) ; i++){ p->mask[i] = 0; p->filt[i] = 0; } p->sec[filtn].found = 0; p->sec[filtn].length = 0; } int filt_is_set(trans *p, int filtn) { if (p->set & ((tflags)(1 << filtn))) return 1; return 0; } int pes_is_set(trans *p, int filtn) { if (p->pes & ((tflags)(1 << filtn))) return 1; return 0; } int pes_is_started(trans *p, int filtn) { if (p->pes_started & ((tflags)(1 << filtn))) return 1; return 0; } int pes_is_start(trans *p, int filtn) { if (p->pes_start & ((tflags)(1 << filtn))) return 1; return 0; } int filt_is_ready(trans *p,int filtn) { if (p->is_full & ((tflags)(1 << filtn))) return 1; return 0; } void trans_filt(u8 *buf, int count, trans *p) { int c=0; //fprintf(stderr,"trans_filt\n"); while (c < count && p->found <1 ){ if ( buf[c] == 0x47) p->found = 1; c++; p->packet[0] = 0x47; } if (c == count) return; while( c < count && p->found < 188 && p->found > 0 ){ p->packet[p->found] = buf[c]; c++; p->found++; } if (p->found == 188){ p->found = 0; filter(p); } if (c < count) trans_filt(buf+c,count-c,p); } void filter(trans *p) { int l,c; int tpid; u8 flag,flags; u8 adapt_length = 0; u8 cpid[2]; // fprintf(stderr,"filter\n"); cpid[0] = p->packet[1]; cpid[1] = p->packet[2]; tpid = get_pid(cpid); flag = cpid[0]; flags = p->packet[3]; if ( flags & ADAPT_FIELD ) { // adaption field adapt_length = p->packet[4]; } c = 5 + adapt_length - (int)(!(flags & ADAPT_FIELD)); if (flags & PAYLOAD){ for ( l = 0; l < MAXFILT ; l++){ if ( filt_is_set(p,l) ) { if ( p->pid[l] == tpid) { if ( pes_is_set(p,l) ){ if (cpid[0] & PAY_START){ p->pes_started |= (tflags) (1 << l); p->pes_start |= (tflags) (1 << l); } else { p->pes_start &= ~ ((tflags) (1 << l)); } pes_filter(p,l,c); } else { sec_filter(p,l,c); } } } } } } void pes_filter(trans *p, int filtn, int off) { int count,c; u8 *buf; if (filtn < 0 || filtn >= MAXFILT) return; count = 188 - off; c = 188*filtn; buf = p->packet+off; if (pes_is_started(p,filtn)){ p->is_full |= (tflags) (1 << filtn); memcpy(p->transbuf+c,buf,count); p->transcount[filtn] = count; } } section *get_filt_sec(trans *p, int filtn) { section *sec; sec = &p->sec[filtn]; p->is_full &= ~((tflags) (1 << filtn) ); return sec; } int get_filt_buf(trans *p, int filtn,u8 **buf) { *buf = p->transbuf+188*filtn; p->is_full &= ~((tflags) (1 << filtn) ); return p->transcount[filtn]; } void sec_filter(trans *p, int filtn, int off) { int i,j; int error; int count,c; u8 *buf, *secbuf; section *sec; // fprintf(stderr,"sec_filter\n"); if (filtn < 0 || filtn >= MAXFILT) return; count = 188 - off; c = 0; buf = p->packet+off; sec = &p->sec[filtn]; secbuf = sec->payload; if(!filt_is_ready(p,filtn)){ p->is_full &= ~((tflags) (1 << filtn) ); sec->found = 0; sec->length = 0; } if ( !sec->found ){ c = buf[c]+1; if (c >= count) return; sec->id = buf[c]; secbuf[0] = buf[c]; c++; sec->found++; sec->length = 0; } while ( c < count && sec->found < 3){ secbuf[sec->found] = buf[c]; c++; sec->found++; } if (c == count) return; if (!sec->length && sec->found == 3){ sec->length |= ((secbuf[1] & 0x0F) << 8); sec->length |= (secbuf[2] & 0xFF); } while ( c < count && sec->found < sec->length+3){ secbuf[sec->found] = buf[c]; c++; sec->found++; } if ( sec->length && sec->found == sec->length+3 ){ error=0; for ( i = 0; i < MASKL; i++){ if (i > 0 ) j=2+i; else j = 0; error += (sec->payload[j]&p->mask[MASKL*filtn+i])^ (p->filt[MASKL*filtn+i]& p->mask[MASKL*filtn+i]); } if (!error){ p->is_full |= (tflags) (1 << filtn); } if (buf[0]+1 < c ) c=count; } if ( c < count ) sec_filter(p, filtn, off); } #define MULT 1024 void write_ps_headr( ps_packet *p, u8 *pts,int fd) { long muxr = 37500; u8 audio_bound = 1; u8 fixed = 0; u8 CSPS = 0; u8 audio_lock = 1; u8 video_lock = 1; u8 video_bound = 1; u8 stream1 = 0XC0; u8 buffer1_scale = 1; u32 buffer1_size = 32; u8 stream2 = 0xE0; u8 buffer2_scale = 1; u32 buffer2_size = 230; init_ps(p); p->mpeg = 2; // SCR = 0 p->scr[0] = 0x44; p->scr[1] = 0x00; p->scr[2] = 0x04; p->scr[3] = 0x00; p->scr[4] = 0x04; p->scr[5] = 0x01; // SCR = PTS p->scr[0] = 0x44 | ((pts[0] >> 3)&0x18) | ((pts[0] >> 4)&0x03); p->scr[1] = 0x00 | ((pts[0] << 4)&0xF0) | ((pts[1] >> 4)&0x0F); p->scr[2] = 0x04 | ((pts[1] << 4)&0xF0) | ((pts[2] >> 4)&0x08) | ((pts[2] >> 5)&0x03); p->scr[3] = 0x00 | ((pts[2] << 3)&0xF8) | ((pts[3] >> 5)&0x07); p->scr[4] = 0x04 | ((pts[3] << 3)&0xF8); p->scr[5] = 0x01; p->mux_rate[0] = (u8)(muxr >> 14); p->mux_rate[1] = (u8)(0xff & (muxr >> 6)); p->mux_rate[2] = (u8)(0x03 | ((muxr & 0x3f) << 2)); p->stuff_length = 0xF8; p->sheader_llength[0] = 0x00; p->sheader_llength[1] = 0x0c; setl_ps(p); p->rate_bound[0] = (u8)(0x80 | (muxr >>15)); p->rate_bound[1] = (u8)(0xff & (muxr >> 7)); p->rate_bound[2] = (u8)(0x01 | ((muxr & 0x7f)<<1)); p->audio_bound = (u8)((audio_bound << 2)|(fixed << 1)|CSPS); p->video_bound = (u8)((audio_lock << 7)| (video_lock << 6)|0x20|video_bound); p->reserved = (u8)(0xFF); p->data[0] = stream2; p->data[1] = (u8) (0xc0 | (buffer2_scale << 5) | (buffer2_size >> 8)); p->data[2] = (u8) (buffer2_size & 0xff); p->data[3] = stream1; p->data[4] = (u8) (0xc0 | (buffer1_scale << 5) | (buffer1_size >> 8)); p->data[5] = (u8) (buffer1_size & 0xff); write_ps(fd, p); kill_ps(p); } void twrite(u8 const *buf) { int l = TS_SIZE; int c = 0; int w; while (l){ w = write(STDOUT_FILENO,buf+c,l); if (w>=0){ l-=w; c+=w; } } } void init_p2t(p2t_t *p, void (*fkt)(u8 const *buf)) { memset(p->pes,0,TS_SIZE); p->counter = 0; p->pos = 0; p->frags = 0; if (fkt) p->t_out = fkt; else p->t_out = twrite; } void clear_p2t(p2t_t *p) { memset(p->pes,0,TS_SIZE); p->counter = 0; p->pos = 0; p->frags = 0; } long int find_pes_header(u8 const *buf, long int length, int *frags) { int c = 0; int found = 0; *frags = 0; while (c < length-3 && !found) { if (buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01) { switch ( buf[c+3] ) { case 0xBA: case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: found = 1; break; default: c++; break; } } else c++; } if (c == length-3 && !found){ if (buf[length-1] == 0x00) *frags = 1; if (buf[length-2] == 0x00 && buf[length-1] == 0x00) *frags = 2; if (buf[length-3] == 0x00 && buf[length-2] == 0x00 && buf[length-1] == 0x01) *frags = 3; return -1; } return c; } void pes_to_ts( u8 const *buf, long int length, u16 pid, p2t_t *p) { int c,c2,l,add; int check,rest; c = 0; c2 = 0; if (p->frags){ check = 0; switch(p->frags){ case 1: if ( buf[c] == 0x00 && buf[c+1] == 0x01 ){ check = 1; c += 2; } break; case 2: if ( buf[c] == 0x01 ){ check = 1; c++; } break; case 3: check = 1; } if(check){ switch ( buf[c] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: p->pes[0] = 0x00; p->pes[1] = 0x00; p->pes[2] = 0x01; p->pes[3] = buf[c]; p->pos=4; memcpy(p->pes+p->pos,buf+c,TS_SIZE-4-p->pos); c += TS_SIZE-4-p->pos; p_to_t(p->pes,TS_SIZE-4,pid,&p->counter, p->t_out); clear_p2t(p); break; default: c=0; break; } } p->frags = 0; } if (p->pos){ c2 = find_pes_header(buf+c,length-c,&p->frags); if (c2 >= 0 && c2 < TS_SIZE-4-p->pos){ l = c2+c; } else l = TS_SIZE-4-p->pos; memcpy(p->pes+p->pos,buf,l); c += l; p->pos += l; p_to_t(p->pes,p->pos,pid,&p->counter, p->t_out); clear_p2t(p); } add = 0; while (c < length){ c2 = find_pes_header(buf+c+add,length-c-add,&p->frags); if (c2 >= 0) { c2 += c+add; if (c2 > c){ p_to_t(buf+c,c2-c,pid,&p->counter, p->t_out); c = c2; clear_p2t(p); add = 0; } else add = 1; } else { l = length-c; rest = l % (TS_SIZE-4); l -= rest; p_to_t(buf+c,l,pid,&p->counter, p->t_out); memcpy(p->pes,buf+c+l,rest); p->pos = rest; c = length; } } } void p_to_t( u8 const *buf, long int length, u16 pid, u8 *counter, void (*ts_write)(u8 const *)) { int l, pes_start; u8 obuf[TS_SIZE]; long int c = 0; pes_start = 0; if ( length > 3 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 ) switch (buf[3]){ case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: pes_start = 1; break; default: break; } while ( c < length ){ memset(obuf,0,TS_SIZE); if (length - c >= TS_SIZE-4){ l = write_ts_header(pid, counter, pes_start , obuf, TS_SIZE-4); memcpy(obuf+l, buf+c, TS_SIZE-l); c += TS_SIZE-l; } else { l = write_ts_header(pid, counter, pes_start , obuf, length-c); memcpy(obuf+l, buf+c, TS_SIZE-l); c = length; } ts_write(obuf); pes_start = 0; } } int write_ps_header(uint8_t *buf, uint32_t SCR, long muxr, uint8_t audio_bound, uint8_t fixed, uint8_t CSPS, uint8_t audio_lock, uint8_t video_lock, uint8_t video_bound, uint8_t stream1, uint8_t buffer1_scale, uint32_t buffer1_size, uint8_t stream2, uint8_t buffer2_scale, uint32_t buffer2_size) { ps_packet p; uint8_t *pts; long lpts; init_ps(&p); lpts = htonl(SCR); pts = (uint8_t *) &lpts; p.mpeg = 2; // SCR = 0 p.scr[0] = 0x44; p.scr[1] = 0x00; p.scr[2] = 0x04; p.scr[3] = 0x00; p.scr[4] = 0x04; p.scr[5] = 0x01; // SCR = PTS p.scr[0] = 0x44 | ((pts[0] >> 3)&0x18) | ((pts[0] >> 4)&0x03); p.scr[1] = 0x00 | ((pts[0] << 4)&0xF0) | ((pts[1] >> 4)&0x0F); p.scr[2] = 0x04 | ((pts[1] << 4)&0xF0) | ((pts[2] >> 4)&0x08) | ((pts[2] >> 5)&0x03); p.scr[3] = 0x00 | ((pts[2] << 3)&0xF8) | ((pts[3] >> 5)&0x07); p.scr[4] = 0x04 | ((pts[3] << 3)&0xF8); p.scr[5] = 0x01; p.mux_rate[0] = (uint8_t)(muxr >> 14); p.mux_rate[1] = (uint8_t)(0xff & (muxr >> 6)); p.mux_rate[2] = (uint8_t)(0x03 | ((muxr & 0x3f) << 2)); p.stuff_length = 0xF8; if (stream1 && stream2){ p.sheader_llength[0] = 0x00; p.sheader_llength[1] = 0x0c; setl_ps(&p); p.rate_bound[0] = (uint8_t)(0x80 | (muxr >>15)); p.rate_bound[1] = (uint8_t)(0xff & (muxr >> 7)); p.rate_bound[2] = (uint8_t)(0x01 | ((muxr & 0x7f)<<1)); p.audio_bound = (uint8_t)((audio_bound << 2)|(fixed << 1)|CSPS); p.video_bound = (uint8_t)((audio_lock << 7)| (video_lock << 6)|0x20|video_bound); p.reserved = (uint8_t)(0xFF >> 1); p.data[0] = stream2; p.data[1] = (uint8_t) (0xc0 | (buffer2_scale << 5) | (buffer2_size >> 8)); p.data[2] = (uint8_t) (buffer2_size & 0xff); p.data[3] = stream1; p.data[4] = (uint8_t) (0xc0 | (buffer1_scale << 5) | (buffer1_size >> 8)); p.data[5] = (uint8_t) (buffer1_size & 0xff); cwrite_ps(buf, &p, PS_HEADER_L2); kill_ps(&p); return PS_HEADER_L2; } else { cwrite_ps(buf, &p, PS_HEADER_L1); kill_ps(&p); return PS_HEADER_L1; } } #define MAX_BASE 80 #define MAX_PATH 256 #define MAX_EXT 10 int break_up_filename(char *name, char *base_name, char *path, char *ext) { int l,i,sstop,sstart; l = strlen(name); sstop = l; sstart = -1; for( i= l-1; i >= 0; i--){ if (sstop == l && name[i] == '.') sstop = i; if (sstart<0 && name[i] == '/') sstart = i+1; } if (sstart < 0) sstart = 0; if (sstop-sstart < MAX_BASE){ strncpy(base_name, name+sstart, sstop-sstart); base_name[sstop-sstart]=0; if(sstart > 0){ if( l - sstop + sstart < MAX_PATH){ strncpy(path, name, sstart); path[sstart] = 0; } else { fprintf(stderr,"PATH too long\n"); return -1; } } else { strcpy(path, "./"); } if(sstop < l){ if( l - sstop -1 < MAX_EXT){ strncpy(ext, name+sstop+1, l-sstop-1); ext[l-sstop-1]=0; } else { fprintf(stderr,"Extension too long\n"); return -1; } } else { strcpy(ext, ""); } } else { fprintf(stderr,"Name too long\n"); return -1; } /* printf("%d %d\n",sstart, sstop); printf("%s %d\n",name, strlen(name)); printf("%s %d\n",base_name, strlen(base_name)); printf("%s %d\n",path,strlen(path)); printf("%s %d\n",ext,strlen(ext)); */ return 0; } int seek_mpg_start(uint8_t *buf, int size) { int found = 0; int c=0; int seq = 0; int mpeg = 0; int mark = 0; while ( !seq ){ while (found != 4){ switch (found) { case 0: if ( buf[c] == 0x00 ) found++; c++; break; case 1: if ( buf[c] == 0x00 ) found++; else found = 0; c++; break; case 2: if ( buf[c] == 0x01 ) found++; else found = 0; if ( buf[c] == 0x00 ) found = 2; c++; break; case 3: if ( (buf[c] & 0xe0) == 0xe0 ) found++; else found = 0; c++; break; } if (c >= size) return -1; } if (found == 4){ mark = c-4; c+=2; if (c >= size) return -1; if ( (buf[c] & 0xC0) == 0x80 ){ mpeg = 2; c += 2; if (c >= size) return -1; c += buf[c]+1; if (c >= size) return -1; } else { mpeg = 1; while( buf[c] == 0xFF ) { c++; if (c >= size) return -1; } if ( (buf[c] & 0xC0) == 0x40) c+=2; if (c >= size) return -1; if ( (buf[c] & 0x30) ){ if ( (buf[c] & 0x30) == 0x20) c+=5; else c+=10; } else c++; if (c >= size) return -1; } if ( buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01 && buf[c+3] == 0xB3 ) seq = 1; } found = 0; } return size-mark; } void write_mpg(int fstart, uint64_t length, int fdin, int fdout) { // uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 }; uint8_t *buf; uint64_t l=0; uint64_t count = 0; struct stat sb; int buf_size; fstat (fdout, &sb); buf_size = sb.st_blksize; buf = (char *) alloca (buf_size + sizeof (int)); lseek(fdin, fstart, SEEK_SET); while ( count < length && (l = read(fdin,buf,buf_size)) >= 0){ if (l > 0) count+=l; write(fdout,buf,l); printf("written %02.2f%%\r",(100.*count)/length); } printf("\n"); //write( fdout, mpeg_end, 4); } #define CHECKBUF (1024*1024) #define ONE_GIG (1024UL*1024UL*1024UL) void split_mpg(char *name, uint64_t size) { char base_name[MAX_BASE]; char path[MAX_PATH]; char ext[MAX_EXT]; char new_name[256]; uint8_t buf[CHECKBUF]; int fdin; int fdout; uint64_t length = 0; uint64_t last; int i; int mark, csize; struct stat sb; if (break_up_filename(name,base_name,path,ext) < 0) exit(1); if ( (fdin = open(name, O_RDONLY|O_LARGEFILE)) < 0){ fprintf(stderr,"Can't open %s\n",name); exit(1); } fstat (fdin, &sb); length = sb.st_size; if ( length < ONE_GIG ) printf("Filelength = %2.2f MB\n", length/1024./1024.); else printf("Filelength = %2.2f GB\n", length/1024./1024./1024.); if ( length < size ) length = size; printf("Splitting %s into Files with size <= %2.2f MB\n",name, size/1024./1024.); csize = CHECKBUF; read(fdin, buf, csize); if ( (mark = seek_mpg_start(buf,csize)) < 0){ fprintf(stderr,"Couldn't find sequence header\n"); exit(1); } last = csize-mark; for ( i = 0 ; i < length/size; i++){ csize = CHECKBUF; if (csize > length-last) csize = length-last; lseek(fdin, last+size-csize, SEEK_SET); read(fdin, buf, csize); if ( (mark = seek_mpg_start(buf,csize)) < 0){ fprintf(stderr,"Couldn't find sequence header\n"); exit(1); } sprintf(new_name,"%s-%03d.%s",base_name,i,ext); printf("writing %s\n",new_name); if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC |O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH)) < 0){ fprintf(stderr,"Can't open %s\n",new_name); exit(1); } write_mpg(last, size-mark, fdin, fdout); last = last + size - mark; } sprintf(new_name,"%s-%03d.%s",base_name,i,ext); printf("writing %s\n",new_name); if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC |O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH)) < 0){ fprintf(stderr,"Can't open %s\n",new_name); exit(1); } write_mpg(last, length-last, fdin, fdout); } void cut_mpg(char *name, uint64_t size) { char base_name[MAX_BASE]; char path[MAX_PATH]; char ext[MAX_EXT]; char new_name[256]; uint8_t buf[CHECKBUF]; int fdin; int fdout; uint64_t length = 0; uint64_t last; int mark, csize; struct stat sb; if (break_up_filename(name,base_name,path,ext) < 0) exit(1); if ( (fdin = open(name, O_RDONLY|O_LARGEFILE)) < 0){ fprintf(stderr,"Can't open %s\n",name); exit(1); } fstat (fdin, &sb); length = sb.st_size; if ( length < ONE_GIG ) printf("Filelength = %2.2f MB\n", length/1024./1024.); else printf("Filelength = %2.2f GB\n", length/1024./1024./1024.); if ( length < size ) length = size; printf("Splitting %s into 2 Files with length %.2f MB and %.2f MB\n", name, size/1024./1024., (length-size)/1024./1024.); csize = CHECKBUF; read(fdin, buf, csize); if ( (mark = seek_mpg_start(buf,csize)) < 0){ fprintf(stderr,"Couldn't find sequence header\n"); exit(1); } last = csize-mark; if (csize > length-last) csize = length-last; lseek(fdin, last+size-csize, SEEK_SET); read(fdin, buf, csize); if ( (mark = seek_mpg_start(buf,csize)) < 0){ fprintf(stderr,"Couldn't find sequence header\n"); exit(1); } sprintf(new_name,"%s-1.%s",base_name,ext); printf("writing %s\n",new_name); if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC |O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH)) < 0){ fprintf(stderr,"Can't open %s\n",new_name); exit(1); } write_mpg(last, size-mark, fdin, fdout); last = last + size - mark; sprintf(new_name,"%s-2.%s",base_name,ext); printf("writing %s\n",new_name); if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC |O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH)) < 0){ fprintf(stderr,"Can't open %s\n",new_name); exit(1); } write_mpg(last, length-last, fdin, fdout); } void write_all (int fd, uint8_t *data, int length) { int r; while (length) { if ((r = write(fd, data, length)) > 0) { data += r; length -= r; } } } void read_all (int fd, uint8_t *data, int length) { int c = 0; while(1) { if( read(fd, data+c, 1) == 1) { c++; if(data[c-1] == '\n') { data[c] = 0; break; } } else { fprintf (stderr, "Error reading socket\n"); exit(1); } } } char *url2host (uint8_t *url, char **name, uint32_t *ip, uint32_t *port) { uint8_t *murl; struct hostent *hoste; struct in_addr haddr; int found_ip = 1; if (!(strncmp(url, "http://", 7))) url += 7; *name = strdup(url); if (!(*name)) { *name = NULL; return (NULL); } murl = url; while (*murl && *murl != ':' && *murl != '/') { if ((*murl < '0' || *murl > '9') && *murl != '.') found_ip = 0; murl++; } (*name)[murl - url] = 0; if (found_ip) { if ((*ip = inet_addr(*name)) == INADDR_NONE) return (NULL); } else { if (!(hoste = gethostbyname(*name))) return (NULL); memcpy (&haddr, hoste->h_addr, sizeof(haddr)); *ip = haddr.s_addr; } if (!*murl || *murl == '/') { *port = 80; return (murl); } *port = atoi(++murl); while (*murl && *murl != '/') murl++; return (murl); } #define ACCEPT "Accept: video/mpeg, video/x-mpegurl, */*\r\n" int http_open (char *url) { char purl[1024], *host, req[1024], *sptr; uint32_t ip; uint32_t port; int sock; int reloc, relocnum = 0; struct sockaddr_in server; int mfd; strncpy (purl, url, 1023); purl[1023] = '\0'; do { host = NULL; strcpy (req, "GET "); if (!(sptr = url2host(purl, &host, &ip, &port))) { fprintf (stderr, "Unknown host\n"); exit (1); } strcat (req, sptr); sprintf (req + strlen(req), " HTTP/1.0\r\nUser-Agent: %s/%s\r\n", "whatever", "you want"); if (host) { sprintf(req + strlen(req), "Host: %s:%u\r\n", host, port); free (host); } strcat (req, ACCEPT); strcat (req, "\r\n"); server.sin_port = htons(port); server.sin_family = AF_INET; server.sin_addr.s_addr = ip; if ((sock = socket(PF_INET, SOCK_STREAM, 6)) < 0) { perror ("socket"); exit (1); } if (connect(sock, (struct sockaddr *)&server, sizeof(server))) { perror ("connect"); exit (1); } write_all (sock, req, strlen(req)); if (!(mfd = fileno(fdopen(sock, "rb")))) { perror ("open"); exit (1); } reloc = 0; purl[0] = '\0'; read_all (mfd, req, 1023); if ((sptr = strchr(req, ' '))) { switch (sptr[1]) { case '2': break; case '3': reloc = 1; default: fprintf (stderr, "HTTP req failed:%s", sptr+1); exit (1); } } do { read_all (mfd,req, 1023); if (!strncmp(req, "Location:", 9)) strncpy (purl, req+10, 1023); } while (req[0] != '\r' && req[0] != '\n'); } while (reloc && purl[0] && relocnum++ < 3); if (reloc) { fprintf (stderr, "Too many HTTP relocations.\n"); exit (1); } return sock; } dvbstream-20090621.orig/mpegtools/remux.c0000644000175000017500000006407707470507565016725 0ustar markmark#include "remux.h" unsigned int bitrates[3][16] = {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; uint32_t freq[4] = {441, 480, 320, 0}; static uint32_t samples[4] = { 384, 1152, 0, 0}; char *frames[3] = {"I-Frame","P-Frame","B-Frame"}; void copy_ptslm(PTS_List *a, PTS_List *b) { a->pos = b->pos; a->PTS = b->PTS; a->dts = b->dts; a->spos = b->spos; } void clear_ptslm(PTS_List *a) { a->pos = 0; a->PTS = 0; a->dts = 0; a->spos = 0; } void init_ptsl(PTS_List *ptsl) { int i; for (i=0;i< MAX_PTS;i++){ clear_ptslm(&ptsl[i]); } } int del_pts(PTS_List *ptsl, int pos, int nr) { int i; int del = 0; for( i = 0; i < nr-1; i++){ if(pos > ptsl[i].pos && pos >= ptsl[i+1].pos) del++; } if(del) for( i = 0; i < nr-del; i++){ copy_ptslm(&ptsl[i], &ptsl[i+del]); } return nr-del; } int del_ptss(PTS_List *ptsl, int pts, int *nb) { int i; int del = 0; int sum = 0; int nr = *nb; for( i = 0; i < nr; i++){ if(pts > ptsl[i].PTS){ del++; sum += ptsl[i].pos; } } if(del) for( i = 0; i < nr-del; i++){ copy_ptslm(&ptsl[i], &ptsl[i+del]); } *nb = nr-del; return sum; } int add_pts(PTS_List *ptsl, uint32_t pts, int pos, int spos, int nr, uint32_t dts) { int i; for ( i=0;i < nr; i++) if (spos && ptsl[i].pos == pos) return nr; if (nr == MAX_PTS) { nr = del_pts(ptsl, ptsl[1].pos+1, nr); } else nr++; i = nr-1; ptsl[i].pos = pos; ptsl[i].spos = spos; ptsl[i].PTS = pts; ptsl[i].dts = dts; return nr; } void add_vpts(Remux *rem, uint8_t *pts) { uint32_t PTS = ntohl(trans_pts_dts(pts)); rem->vptsn = add_pts(rem->vpts_list, PTS, rem->vwrite, rem->awrite, rem->vptsn, PTS); } void add_apts(Remux *rem, uint8_t *pts) { uint32_t PTS = ntohl(trans_pts_dts(pts)); rem->aptsn = add_pts(rem->apts_list, PTS, rem->awrite, rem->vwrite, rem->aptsn, PTS); } void del_vpts(Remux *rem) { rem->vptsn = del_pts(rem->vpts_list, rem->vread, rem->vptsn); } void del_apts(Remux *rem) { rem->aptsn = del_pts(rem->apts_list, rem->aread, rem->aptsn); } void copy_framelm(FRAME_List *a, FRAME_List *b) { a->type = b->type; a->pos = b->pos; a->FRAME = b->FRAME; a->time = b->time; a->pts = b->pts; a->dts = b->dts; } void clear_framelm(FRAME_List *a) { a->type = 0; a->pos = 0; a->FRAME = 0; a->time = 0; a->pts = 0; a->dts = 0; } void init_framel(FRAME_List *framel) { int i; for (i=0;i< MAX_FRAME;i++){ clear_framelm(&framel[i]); } } int del_frame(FRAME_List *framel, int pos, int nr) { int i; int del = 0; for( i = 0; i < nr-1; i++){ if(pos > framel[i].pos && pos >= framel[i+1].pos) del++; } if(del) for( i = 0; i < nr-del; i++){ copy_framelm(&framel[i], &framel[i+del]); } return nr-del; } int add_frame(FRAME_List *framel, uint32_t frame, int pos, int type, int nr, uint32_t time, uint32_t pts, uint32_t dts) { int i; if (nr == MAX_FRAME) { nr = del_frame(framel, framel[1].pos+1, nr); } else nr++; i = nr-1; framel[i].type = type; framel[i].pos = pos; framel[i].FRAME = frame; framel[i].time = time; framel[i].pts = pts; framel[i].dts = dts; return nr; } void add_vframe(Remux *rem, uint32_t frame, long int pos, int type, int time, uint32_t pts, uint32_t dts) { rem->vframen = add_frame(rem->vframe_list, frame, pos, type, rem->vframen, time, pts, dts); } void add_aframe(Remux *rem, uint32_t frame, long int pos, uint32_t pts) { rem->aframen = add_frame(rem->aframe_list, frame, pos, 0, rem->aframen, 0, pts, pts); } void del_vframe(Remux *rem) { rem->vframen = del_frame(rem->vframe_list, rem->vread, rem->vframen); } void del_aframe(Remux *rem) { rem->aframen = del_frame(rem->aframe_list, rem->aread, rem->aframen); } void printpts(uint32_t pts) { fprintf(stderr,"%2d:%02d:%02d.%03d", (int)(pts/90000.)/3600, ((int)(pts/90000.)%3600)/60, ((int)(pts/90000.)%3600)%60, (((int)(pts/90.)%3600000)%60000)%1000 ); } void find_vframes( Remux *rem, uint8_t *buf, int l) { int c = 0; int type; uint32_t time = 0; int hour; int min; int sec; u64 pts=0; u64 dts=0; uint32_t tempref = 0; while ( c < l - 6){ if (buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01 && buf[c+3] == 0xB8) { c += 4; hour = (int)((buf[c]>>2)& 0x1F); min = (int)(((buf[c]<<4)& 0x30)| ((buf[c+1]>>4)& 0x0F)); sec = (int)(((buf[c+1]<<3)& 0x38)| ((buf[c+2]>>5)& 0x07)); time = 3600*hour + 60*min + sec; if ( rem->time_off){ time = (uint32_t)((u64)time - rem->time_off); hour = time/3600; min = (time%3600)/60; sec = (time%3600)%60; /* buf[c] |= (hour & 0x1F) << 2; buf[c] |= (min & 0x30) >> 4; buf[c+1] |= (min & 0x0F) << 4; buf[c+1] |= (sec & 0x38) >> 3; buf[c+2] |= (sec & 0x07) >> 5;*/ } rem->group++; rem->groupframe = 0; } if ( buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01 && buf[c+3] == 0x00) { c += 4; tempref = (buf[c+1]>>6) & 0x03; tempref |= buf[c] << 2; type = ((buf[c+1]&0x38) >>3); if ( rem->video_info.framerate){ pts = ((u64)rem->vframe + tempref + 1 - rem->groupframe ) * 90000ULL /rem->video_info.framerate + rem->vpts_off; dts = (u64)rem->vframe * 90000ULL/ rem->video_info.framerate + rem->vpts_off; /* fprintf(stderr,"MYPTS:"); printpts((uint32_t)pts-rem->vpts_off); fprintf(stderr," REALPTS:"); printpts(rem->vpts_list[rem->vptsn-1].PTS-rem->vpts_off); fprintf(stderr," DIFF:"); printpts(pts-(u64)rem->vpts_list[rem->vptsn-1].PTS); fprintf(stderr," DIST: %4d",-rem->vpts_list[rem->vptsn-1].pos+(rem->vwrite+c-4)); //fprintf(stderr," ERR: %3f",(double)(-rem->vpts_list[rem->vptsn-1].PTS+pts)/(rem->vframe+1)); fprintf(stderr,"\r"); */ rem->vptsn = add_pts(rem->vpts_list,(uint32_t)pts ,rem->vwrite+c-4, rem->awrite, rem->vptsn, (uint32_t)dts); } rem->vframe++; rem->groupframe++; add_vframe( rem, rem->vframe, rem->vwrite+c, type, time, pts, dts); } else c++; } } void find_aframes( Remux *rem, uint8_t *buf, int l) { int c = 0; u64 pts = 0; int sam; uint32_t fr; while ( c < l - 2){ if ( buf[c] == 0xFF && (buf[c+1] & 0xF8) == 0xF8) { c += 2; if ( rem->audio_info.layer >= 0){ sam = samples[3-rem->audio_info.layer]; fr = freq[rem->audio_info.frequency] ; pts = ( (u64)rem->aframe * sam * 900ULL)/fr + rem->apts_off; /* fprintf(stderr,"MYPTS:"); printpts((uint32_t)pts-rem->apts_off); fprintf(stderr," REALPTS:"); printpts(rem->apts_list[rem->aptsn-1].PTS-rem->apts_off); fprintf(stderr," DIFF:"); printpts((uint32_t)((u64)rem->apts_list[rem->aptsn-1].PTS-pts)); fprintf(stderr," DIST: %4d",-rem->apts_list[rem->aptsn-1].pos+(rem->awrite+c-2)); fprintf(stderr,"\r"); */ rem->aptsn = add_pts(rem->apts_list,(uint32_t)pts ,rem->awrite+c-2, rem->vwrite, rem->aptsn, (uint32_t)pts); } rem->aframe++; add_aframe( rem, rem->aframe, rem->awrite+c, pts); } else c++; } } int refill_buffy(Remux *rem) { pes_packet pes; int count = 0; int acount, vcount; ringbuffy *vbuf = &rem->vid_buffy; ringbuffy *abuf = &rem->aud_buffy; int fin = rem->fin; acount = abuf->size-ring_rest(abuf); vcount = vbuf->size-ring_rest(vbuf); while ( acount > MAX_PLENGTH && vcount > MAX_PLENGTH && count < 10){ int neof; count++; init_pes(&pes); if ((neof = read_pes(fin,&pes)) <= 0) return -1; switch(pes.stream_id){ case AUDIO_STREAM_S ... AUDIO_STREAM_E: rem->apes++; if( rem->audio_info.layer < 0 && (pes.flags2 & PTS_DTS) ) add_apts(rem, pes.pts); find_aframes( rem, pes.pes_pckt_data, pes.length); ring_write(abuf,(char *)pes.pes_pckt_data,pes.length); rem->awrite += pes.length; break; case VIDEO_STREAM_S ... VIDEO_STREAM_E: rem->vpes++; if( !rem->video_info.framerate && (pes.flags2 & PTS_DTS) ) add_vpts(rem, pes.pts); find_vframes( rem, pes.pes_pckt_data, pes.length); ring_write(vbuf,(char *)pes.pes_pckt_data,pes.length); rem->vwrite += pes.length; break; } acount = abuf->size-ring_rest(abuf); vcount = vbuf->size-ring_rest(vbuf); kill_pes(&pes); } if (count < 10) return 0; return 1; } int vring_read( Remux *rem, uint8_t *buf, int l) { int c = 0; int r = 0; if (ring_rest(&rem->vid_buffy) <= l) r = refill_buffy(rem); if (r) return -1; c = ring_read(&rem->vid_buffy, (char *) buf, l); rem->vread += c; del_vpts(rem); del_vframe(rem); return c; } int aring_read( Remux *rem, uint8_t *buf, int l) { int c = 0; int r = 0; if (ring_rest(&rem->aud_buffy) <= l) r = refill_buffy(rem); if (r) return -1; c = ring_read(&rem->aud_buffy, (char *)buf, l); rem->aread += c; del_apts(rem); del_aframe(rem); return c; } int vring_peek( Remux *rem, uint8_t *buf, int l, long off) { int c = 0; if (ring_rest(&rem->vid_buffy) <= l) refill_buffy(rem); c = ring_peek(&rem->vid_buffy, (char *) buf, l, off); return c; } int aring_peek( Remux *rem, uint8_t *buf, int l, long off) { int c = 0; if (ring_rest(&rem->aud_buffy) <= l) refill_buffy(rem); c = ring_peek(&rem->aud_buffy, (char *)buf, l, off); return c; } int get_video_info(Remux *rem) { uint8_t buf[12]; uint8_t *headr; int found = 0; int sw; long off = 0; int form = -1; ringbuffy *vid_buffy = &rem->vid_buffy; VideoInfo *vi = &rem->video_info; while (found < 4 && ring_rest(vid_buffy)){ uint8_t b[3]; vring_peek( rem, b, 4, 0); if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 && b[3] == 0xb3) found = 4; else { off++; vring_read( rem, b, 1); } } rem->vframe = rem->vframen-1; if (! found) return -1; buf[0] = 0x00; buf[1] = 0x00; buf[2] = 0x01; buf[3] = 0xb3; headr = buf+4; if(vring_peek(rem, buf, 12, 0) < 12) return -1; vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); sw = (int)((headr[3]&0xF0) >> 4) ; switch( sw ){ case 1: fprintf(stderr,"Videostream: ASPECT: 1:1"); vi->aspect_ratio = 100; break; case 2: fprintf(stderr,"Videostream: ASPECT: 4:3"); vi->aspect_ratio = 133; break; case 3: fprintf(stderr,"Videostream: ASPECT: 16:9"); vi->aspect_ratio = 177; break; case 4: fprintf(stderr,"Videostream: ASPECT: 2.21:1"); vi->aspect_ratio = 221; break; case 5 ... 15: fprintf(stderr,"Videostream: ASPECT: reserved"); vi->aspect_ratio = 0; break; default: vi->aspect_ratio = 0; return -1; } fprintf(stderr," Size = %dx%d",vi->horizontal_size,vi->vertical_size); sw = (int)(headr[3]&0x0F); switch ( sw ) { case 1: fprintf(stderr," FRate: 23.976 fps"); vi->framerate = 24000/1001.; form = -1; break; case 2: fprintf(stderr," FRate: 24 fps"); vi->framerate = 24; form = -1; break; case 3: fprintf(stderr," FRate: 25 fps"); vi->framerate = 25; form = VIDEO_MODE_PAL; break; case 4: fprintf(stderr," FRate: 29.97 fps"); vi->framerate = 30000/1001.; form = VIDEO_MODE_NTSC; break; case 5: fprintf(stderr," FRate: 30 fps"); vi->framerate = 30; form = VIDEO_MODE_NTSC; break; case 6: fprintf(stderr," FRate: 50 fps"); vi->framerate = 50; form = VIDEO_MODE_PAL; break; case 7: fprintf(stderr," FRate: 60 fps"); vi->framerate = 60; form = VIDEO_MODE_NTSC; break; } rem->dts_delay = (int)(7.0/vi->framerate/2.0*90000); vi->bit_rate = 400*(((headr[4] << 10) & 0x0003FC00UL) | ((headr[5] << 2) & 0x000003FCUL) | (((headr[6] & 0xC0) >> 6) & 0x00000003UL)); fprintf(stderr," BRate: %.2f Mbit/s",(vi->bit_rate)/1000000.); fprintf(stderr,"\n"); vi->video_format = form; /* marker_bit (&video_bs, 1); vi->vbv_buffer_size = getbits (&video_bs, 10); vi->CSPF = get1bit (&video_bs); */ return form; } int get_audio_info( Remux *rem) { uint8_t *headr; uint8_t buf[3]; long off = 0; int found = 0; ringbuffy *aud_buffy = &rem->aud_buffy; AudioInfo *ai = &rem->audio_info; while(!ring_rest(aud_buffy) && !refill_buffy(rem)); while (found < 2 && ring_rest(aud_buffy)){ uint8_t b[2]; refill_buffy(rem); aring_peek( rem, b, 2, 0); if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) found = 2; else { off++; aring_read( rem, b, 1); } } if (!found) return -1; rem->aframe = rem->aframen-1; if (aring_peek(rem, buf, 3, 0) < 1) return -1; headr = buf+2; ai->layer = (buf[1] & 0x06) >> 1; fprintf(stderr,"Audiostream: Layer: %d", 4-ai->layer); ai->bit_rate = bitrates[(3-ai->layer)][(headr[0] >> 4 )]*1000; if (ai->bit_rate == 0) fprintf (stderr," Bit rate: free"); else if (ai->bit_rate == 0xf) fprintf (stderr," BRate: reserved"); else fprintf (stderr," BRate: %d kb/s", ai->bit_rate/1000); ai->frequency = (headr[0] & 0x0c ) >> 2; if (ai->frequency == 3) fprintf (stderr, " Freq: reserved\n"); else fprintf (stderr," Freq: %2.1f kHz\n", freq[ai->frequency]/10.); return 0; } void init_remux(Remux *rem, int fin, int fout, int mult) { rem->video_info.framerate = 0; rem->audio_info.layer = -1; rem->fin = fin; rem->fout = fout; ring_init(&rem->vid_buffy, 40*BUFFYSIZE*mult); ring_init(&rem->aud_buffy, BUFFYSIZE*mult); init_ptsl(rem->vpts_list); init_ptsl(rem->apts_list); init_framel(rem->vframe_list); init_framel(rem->aframe_list); rem->vptsn = 0; rem->aptsn = 0; rem->vframen = 0; rem->aframen = 0; rem->vframe = 0; rem->aframe = 0; rem->vcframe = 0; rem->acframe = 0; rem->vpts = 0; rem->vdts = 0; rem->apts_off = 0; rem->vpts_off = 0; rem->apts_delay= 0; rem->vpts_delay= 0; rem->dts_delay = 0; rem->apts = 0; rem->vpes = 0; rem->apes = 0; rem->vpts_old = 0; rem->apts_old = 0; rem->SCR = 0; rem->vwrite = 0; rem->awrite = 0; rem->vread = 0; rem->aread = 0; rem->group = 0; rem->groupframe= 0; rem->pack_size = 0; rem->muxr = 0; rem->time_off = 0; } uint32_t bytes2pts(int bytes, int rate) { if (bytes < 0xFFFFFFFFUL/720000UL) return (uint32_t)(bytes*720000UL/rate); else return (uint32_t)(bytes/rate*720000UL); } long pts2bytes( uint32_t pts, int rate) { if (pts < 0xEFFFFFFFUL/rate) return (pts*rate/720000); else return (pts* (rate/720000)); } int write_audio_pes( Remux *rem, uint8_t *buf, int *alength) { int add; int pos = 0; int p = 0; uint32_t pts = 0; int stuff = 0; int length = *alength; if (!length) return 0; p = PS_HEADER_L1+PES_H_MIN; if (rem->apts_old != rem->apts){ pts = (uint32_t)((u64)rem->apts + rem->apts_delay - rem->apts_off); p += 5; } if ( length+p >= rem->pack_size){ length = rem->pack_size; } else { if (rem->pack_size-length-p <= PES_MIN){ stuff = rem->pack_size - length; length = rem->pack_size; } else length = length+p; } pos = write_ps_header(buf,rem->SCR,rem->muxr, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); pos += write_pes_header( 0xC0, length-pos, pts, buf+pos, stuff); add = aring_read( rem, buf+pos, length-pos); *alength = add; if (add < 0) return -1; pos += add; rem->apts_old = rem->apts; rem->apts = rem->apts_list[0].PTS; if (pos+PES_MIN < rem->pack_size){ pos += write_pes_header( PADDING_STREAM, rem->pack_size-pos, 0, buf+pos, 0); pos = rem->pack_size; } if (pos != rem->pack_size) { fprintf(stderr,"apos: %d\n",pos); exit(1); } return pos; } int write_video_pes( Remux *rem, uint8_t *buf, int *vlength) { int add; int pos = 0; int p = 0; uint32_t pts = 0; uint32_t dts = 0; int stuff = 0; int length = *vlength; long diff = 0; if (! length) return 0; p = PS_HEADER_L1+PES_H_MIN; if (rem->vpts_old != rem->vpts){ pts = (uint32_t)((u64)rem->vpts + rem->vpts_delay - rem->vpts_off); p += 5; } if ( length+p >= rem->pack_size){ length = rem->pack_size; } else { if (rem->pack_size - length - p <= PES_MIN){ stuff = rem->pack_size - length; length = rem->pack_size; } else length = length+p; } pos = write_ps_header(buf,rem->SCR,rem->muxr, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); pos += write_pes_header( 0xE0, length-pos, pts, buf+pos, stuff); add = vring_read( rem, buf+pos, length-pos); *vlength = add; if (add < 0) return -1; pos += add; rem->vpts_old = rem->vpts; dts = rem->vdts; rem->vpts = rem->vpts_list[0].PTS; rem->vdts = rem->vpts_list[0].dts; if ( diff > 0) rem->SCR += diff; if (pos+PES_MIN < rem->pack_size){ // fprintf(stderr,"vstuffing: %d \n",rem->pack_size-pos); pos += write_pes_header( PADDING_STREAM, rem->pack_size-pos, 0, buf+pos, 0); pos = rem->pack_size; } return pos; } void print_info( Remux *rem , int ret) { int newtime = 0; static int time = 0; int i = 0; while(! newtime && i < rem->vframen) { if( (newtime = rem->vframe_list[i].time)) break; i++; } if (newtime) time = newtime; fprintf(stderr,"SCR:"); printpts(rem->SCR); fprintf(stderr," VDTS:"); printpts((uint32_t)((u64)rem->vdts - rem->vpts_off + rem->vpts_delay)); fprintf(stderr," APTS:"); printpts((uint32_t)((u64)rem->apts - rem->apts_off + rem->apts_delay)); fprintf(stderr," TIME:%2d:", time/3600); fprintf(stderr,"%02d:", (time%3600)/60); fprintf(stderr,"%02d", (time%3600)%60); if (ret) fprintf(stderr,"\n"); else fprintf(stderr,"\r"); } void remux(int fin, int fout, int pack_size, int mult) { Remux rem; long ptsdiff; uint8_t buf[MAX_PACK_L]; long pos = 0; int r = 0; int i, r1, r2; long packets = 0; uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 }; uint32_t SCR_inc = 0; int data_size; long vbuf, abuf; long vbuf_max, abuf_max; PTS_List abufl[MAX_PTS]; PTS_List vbufl[MAX_PTS]; int abufn = 0; int vbufn = 0; u64 pts_d = 0; int ok_audio; int ok_video; uint32_t apos = 0; uint32_t vpos = 0; int vpack_size = 0; int apack_size = 0; init_ptsl(abufl); init_ptsl(vbufl); init_remux(&rem, fin, fout, mult); rem.pack_size = pack_size; data_size = pack_size - MAX_H_SIZE; fprintf(stderr,"pack_size: %d header_size: %d data size: %d\n", pack_size, MAX_H_SIZE, data_size); refill_buffy(&rem); fprintf(stderr,"Package size: %d\n",pack_size); if ( get_video_info(&rem) < 0 ){ fprintf(stderr,"ERROR: Can't find valid video stream\n"); exit(1); } i = 0; while(! rem.time_off && i < rem.vframen) { if( (rem.time_off = rem.vframe_list[i].time)) break; i++; } if ( get_audio_info(&rem) < 0 ){ fprintf(stderr,"ERROR: Can't find valid audio stream\n"); exit(1); } rem.vpts = rem.vpts_list[0].PTS; rem.vdts = rem.vpts; rem.vpts_off = rem.vpts; fprintf(stderr,"Video start PTS = %fs \n",rem.vpts_off/90000.); rem.apts = rem.apts_list[0].PTS; rem.apts_off = rem.apts; ptsdiff = rem.vpts - rem.apts; if (ptsdiff > 0) rem.vpts_off -= ptsdiff; else rem.apts_off -= -ptsdiff; fprintf(stderr,"Audio start PTS = %fs\n",rem.apts_off/90000.); fprintf(stderr,"Difference Video - Audio = %fs\n",ptsdiff/90000.); fprintf(stderr,"Time offset = %ds\n",rem.time_off); rem.muxr = (rem.video_info.bit_rate + rem.audio_info.bit_rate)/400; fprintf(stderr,"MUXRATE: %.2f Mb/sec\n",rem.muxr/2500.); SCR_inc = 1800 * pack_size / rem.muxr; r = 0; while ( rem.vptsn < 2 && !r) r = refill_buffy(&rem); r = 0; while ( rem.aptsn < 2 && !r) r = refill_buffy(&rem); //rem.vpts_delay = (uint32_t)(2*90000ULL* (u64)pack_size/rem.muxr); rem.vpts_delay = rem.dts_delay; rem.apts_delay = rem.vpts_delay; vbuf_max = 29440; abuf_max = 4096; vbuf = 0; abuf = 0; pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, 1, 1, 1, 0xC0, 0, 32, 0xE0, 1, 230); pos += write_pes_header( PADDING_STREAM, pack_size-pos, 0, buf+pos,0); pos = rem.pack_size; write( fout, buf, pos); apos = rem.aread; vpos = rem.vread; print_info( &rem, 1 ); while( ring_rest(&rem.aud_buffy) && ring_rest(&rem.vid_buffy) ){ uint32_t next_apts; uint32_t next_vdts; int asize, vsize; r1 = 0; r2 = 0; while ( rem.aframen < 2 && !r1) r1 = refill_buffy(&rem); while ( rem.vframen < 2 && !r2) r2 = refill_buffy(&rem); if (r1 && r2) break; if ( !r1 && apos <= rem.aread) apos = rem.aframe_list[1].pos; if ( !r2 && vpos <= rem.vread) vpos = rem.vframe_list[1].pos; apack_size = apos - rem.aread; vpack_size = vpos - rem.vread; next_vdts = (uint32_t)((u64)rem.vdts + rem.vpts_delay - rem.vpts_off) ; ok_video = ( rem.SCR < next_vdts); next_apts = (uint32_t)((u64)rem.apts + rem.apts_delay - rem.apts_off) ; ok_audio = ( rem.SCR < next_apts); asize = (apack_size > data_size ? data_size: apack_size); vsize = (vpack_size > data_size ? data_size: vpack_size); fprintf(stderr,"vframen: %d aframen: %d v_ok: %d a_ok: %d v_buf: %d a_buf: %d vpacks: %d apacks: %d\n",rem.vframen,rem.aframen, ok_video, ok_audio, (int)vbuf,(int)abuf,vsize, asize); if( vbuf+vsize < vbuf_max && vsize && ok_audio ){ fprintf(stderr,"1 "); pos = write_video_pes( &rem, buf, &vpack_size); write( fout, buf, pos); vbuf += vpack_size; vbufn = add_pts( vbufl, rem.vdts, vpack_size, 0, vbufn, 0); packets++; } else if ( abuf+asize < abuf_max && asize && ok_video ){ fprintf(stderr,"2 "); pos = write_audio_pes( &rem, buf, &apack_size); write( fout, buf, pos); abuf += apack_size; abufn = add_pts( abufl, rem.apts, apack_size, 0, abufn, 0); packets++; } else if ( abuf+asize < abuf_max && asize && !ok_audio){ fprintf(stderr,"3 "); pos = write_audio_pes( &rem, buf, &apack_size); write( fout, buf, pos); abuf += apack_size; abufn = add_pts( abufl, rem.apts, apack_size, 0, abufn, 0); packets++; } else if (vbuf+vsize < vbuf_max && vsize && !ok_video){ fprintf(stderr,"4 "); pos = write_video_pes( &rem, buf, &vpack_size); write( fout, buf, pos); vbuf += vpack_size; vbufn = add_pts( vbufl, rem.vdts, vpack_size, 0, vbufn, 0); packets++; } else { fprintf(stderr,"5 "); pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); pos += write_pes_header( PADDING_STREAM, pack_size-pos, 0, buf+pos, 0); write( fout, buf, pos); } //fprintf(stderr,"vbufn: %d abufn: %d ", vbufn,abufn); //fprintf(stderr,"vbuf: %5d abuf: %4d\n", vbuf,abuf); if (rem.SCR > rem.vdts+rem.vpts_off -rem.vpts_delay) rem.SCR = rem.vdts-rem.vpts_off; rem.SCR = (uint32_t)((u64) rem.SCR + SCR_inc); if ( rem.apts_off + rem.SCR < rem.apts_delay ) pts_d = 0; else pts_d = (u64) rem.SCR + rem.apts_off - rem.apts_delay; abuf -= del_ptss( abufl, (uint32_t) pts_d, &abufn); if ( rem.vpts_off + rem.SCR < rem.vpts_delay ) pts_d = 0; else pts_d = (u64) rem.SCR + rem.vpts_off - rem.vpts_delay; vbuf -= del_ptss( vbufl, (uint32_t) pts_d, &vbufn); print_info( &rem, 1); //fprintf(stderr,"vbufn: %d abufn: %d ", vbufn,abufn); //fprintf(stderr,"vbuf: %5d abuf: %4d\n\n", vbuf,abuf); } pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); pos += write_pes_header( PADDING_STREAM, pack_size-pos-4, 0, buf+pos, 0); pos = rem.pack_size-4; write( fout, buf, pos); write( fout, mpeg_end, 4); fprintf(stderr,"\ndone\n"); } typedef struct pes_buffer_s{ ringbuffy pes_buffy; uint8_t type; PTS_List pts_list[MAX_PTS]; FRAME_List frame_list[MAX_FRAME]; int pes_size; uint64_t written; uint64_t read; } PESBuffer; void init_PESBuffer(PESBuffer *pbuf, int pes_size, int buf_size, uint8_t type) { init_framel( pbuf->frame_list); init_ptsl( pbuf->pts_list); ring_init( &pbuf->pes_buffy, buf_size); pbuf->pes_size = pes_size; pbuf->type = type; pbuf->written = 0; pbuf->read = 0; } #define MAX_PBUF 4 typedef struct remux_s{ PESBuffer pbuf_list[MAX_PBUF]; int num_pbuf; } REMUX; void init_REMUX(REMUX *rem) { rem->num_pbuf = 0; } #define REPACK 2048 #define ABUF_SIZE REPACK*1024 #define VBUF_SIZE REPACK*10240 void remux_main(uint8_t *buf, int count, p2p *p) { int i, b; int bufsize = 0; PESBuffer *pbuf; REMUX *rem = (REMUX *) p->data; uint8_t type = buf[3]; int *npbuf = &(rem->num_pbuf); switch ( type ){ case PRIVATE_STREAM1: bufsize = ABUF_SIZE; case VIDEO_STREAM_S ... VIDEO_STREAM_E: if (!bufsize) bufsize = VBUF_SIZE; case AUDIO_STREAM_S ... AUDIO_STREAM_E: if (!bufsize) bufsize = ABUF_SIZE; b = -1; for ( i = 0; i < *npbuf; i++){ if ( type == rem->pbuf_list[i].type ){ b = i; break; } } if (b < 0){ if ( *npbuf < MAX_PBUF ){ init_PESBuffer(&rem->pbuf_list[*npbuf], p->repack+6, bufsize, type); b = *npbuf; (*npbuf)++; } else { fprintf(stderr,"Not enough PES buffers\n"); exit(1); } } break; default: return; } pbuf = &(rem->pbuf_list[b]); if (ring_write(&(pbuf->pes_buffy),(char *)buf,count) != count){ fprintf(stderr,"buffer overflow type 0x%2x\n",type); exit(1); } else { pbuf->written += count; if ((p->flag2 & PTS_DTS_FLAGS)){ uint32_t PTS = ntohl(trans_pts_dts(p->pts)); add_pts(pbuf->pts_list, PTS, pbuf->written, pbuf->written, 0, 0); } p->flag2 = 0; } } void output_mux(p2p *p) { int i, filling; PESBuffer *pbuf; ringbuffy *pes_buffy; REMUX *rem = (REMUX *) p->data; int repack = p->repack; int npbuf = rem->num_pbuf; for ( i = 0; i < npbuf; i++){ pbuf = &(rem->pbuf_list[i]); pes_buffy = &pbuf->pes_buffy; filling = pes_buffy->size - ring_rest(pes_buffy); if (filling/(2 *repack)){ pbuf->read += ring_read_file(pes_buffy, p->fd1, (filling/repack)*repack); } } } #define SIZE 32768 void remux2(int fdin, int fdout) { p2p p; int count = 1; uint8_t buf[SIZE]; uint64_t length = 0; uint64_t l = 0; int verb = 0; REMUX rem; init_p2p(&p, remux_main, REPACK); p.fd1 = fdout; p.data = (void *) &rem; if (fdin != STDIN_FILENO) verb = 1; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } while (count > 0){ count = read(fdin,buf,SIZE); l += count; if (verb) fprintf(stderr,"Writing %2.2f %%\r", 100.*l/length); get_pes(buf,count,&p,pes_repack); output_mux(&p); } } dvbstream-20090621.orig/mpegtools/transform.h0000644000175000017500000001376007470507601017565 0ustar markmark/* * mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at marcus@convergence.de, * the project's page is at http://linuxtv.org/dvb/ */ #ifndef _TS_TRANSFORM_H_ #define _TS_TRANSFORM_H_ #include #include #include #include #include "remux.h" #define PROG_STREAM_MAP 0xBC #ifndef PRIVATE_STREAM1 #define PRIVATE_STREAM1 0xBD #endif #define PADDING_STREAM 0xBE #ifndef PRIVATE_STREAM2 #define PRIVATE_STREAM2 0xBF #endif #define AUDIO_STREAM_S 0xC0 #define AUDIO_STREAM_E 0xDF #define VIDEO_STREAM_S 0xE0 #define VIDEO_STREAM_E 0xEF #define ECM_STREAM 0xF0 #define EMM_STREAM 0xF1 #define DSM_CC_STREAM 0xF2 #define ISO13522_STREAM 0xF3 #define PROG_STREAM_DIR 0xFF #define BUFFYSIZE 10*MAX_PLENGTH #define MAX_PTS 8192 #define MAX_FRAME 8192 #define MAX_PACK_L 4096 #define PS_HEADER_L1 14 #define PS_HEADER_L2 (PS_HEADER_L1+18) #define MAX_H_SIZE (PES_H_MIN + PS_HEADER_L1 + 5) #define PES_MIN 7 #define PES_H_MIN 9 //flags2 #define PTS_DTS_FLAGS 0xC0 #define ESCR_FLAG 0x20 #define ES_RATE_FLAG 0x10 #define DSM_TRICK_FLAG 0x08 #define ADD_CPY_FLAG 0x04 #define PES_CRC_FLAG 0x02 #define PES_EXT_FLAG 0x01 //pts_dts flags #define PTS_ONLY 0x80 #define PTS_DTS 0xC0 #define TS_SIZE 188 #define TRANS_ERROR 0x80 #define PAY_START 0x40 #define TRANS_PRIO 0x20 #define PID_MASK_HI 0x1F //flags #define TRANS_SCRMBL1 0x80 #define TRANS_SCRMBL2 0x40 #define ADAPT_FIELD 0x20 #define PAYLOAD 0x10 #define COUNT_MASK 0x0F // adaptation flags #define DISCON_IND 0x80 #define RAND_ACC_IND 0x40 #define ES_PRI_IND 0x20 #define PCR_FLAG 0x10 #define OPCR_FLAG 0x08 #define SPLICE_FLAG 0x04 #define TRANS_PRIV 0x02 #define ADAP_EXT_FLAG 0x01 // adaptation extension flags #define LTW_FLAG 0x80 #define PIECE_RATE 0x40 #define SEAM_SPLICE 0x20 #define MAX_PLENGTH 0xFFFF #define MMAX_PLENGTH (8*MAX_PLENGTH) #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define P2P_LENGTH 2048 enum{NOPES, AUDIO, VIDEO}; typedef struct p2pstruct { int found; uint8_t buf[MMAX_PLENGTH]; uint8_t cid; uint32_t plength; uint8_t plen[2]; uint8_t flag1; uint8_t flag2; uint8_t hlength; uint8_t pts[5]; int mpeg; uint8_t check; int fd1; int fd2; int es; int filter; int which; int done; int repack; uint16_t bigend_repack; void (*func)(uint8_t *buf, int count, struct p2pstruct *p); int startv; int starta; int64_t apts; int64_t vpts; uint16_t pid; uint16_t pida; uint16_t pidv; uint8_t acounter; uint8_t vcounter; uint8_t count0; uint8_t count1; void *data; } p2p; uint32_t trans_pts_dts(uint8_t *pts); int write_ts_header(uint16_t pid, uint8_t *counter, int pes_start, uint8_t *buf, uint8_t length); uint16_t get_pid(uint8_t *pid); void init_p2p(p2p *p, void (*func)(uint8_t *buf, int count, p2p *p), int repack); void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)); void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)); void pes_repack(p2p *p); void setup_pes2ts( p2p *p, uint32_t pida, uint32_t pidv, void (*ts_write)(uint8_t *buf, int count, p2p *p)); void kpes_to_ts( p2p *p,uint8_t *buf ,int count ); void setup_ts2pes( p2p *pa, p2p *pv, uint32_t pida, uint32_t pidv, void (*pes_write)(uint8_t *buf, int count, p2p *p)); void kts_to_pes( p2p *p, uint8_t *buf); void pes_repack(p2p *p); void extract_from_pes(int fdin, int fdout, uint8_t id, int es); int64_t pes_dmx(int fdin, int fdouta, int fdoutv, int es); void pes_to_ts2( int fdin, int fdout, uint16_t pida, uint16_t pidv); void ts_to_pes( int fdin, uint16_t pida, uint16_t pidv, int pad); int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr); int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr); int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr); //instant repack typedef struct ipack_s { int size; int size_orig; int found; int ps; int has_ai; int has_vi; AudioInfo ai; VideoInfo vi; uint8_t *buf; uint8_t cid; uint32_t plength; uint8_t plen[2]; uint8_t flag1; uint8_t flag2; uint8_t hlength; uint8_t pts[5]; uint8_t last_pts[5]; int mpeg; uint8_t check; int which; int done; void *data; void (*func)(uint8_t *buf, int size, void *priv); int count; int start; int fd; } ipack; void instant_repack (uint8_t *buf, int count, ipack *p); void init_ipack(ipack *p, int size, void (*func)(uint8_t *buf, int size, void *priv), int pad); void free_ipack(ipack * p); void send_ipack(ipack *p); void reset_ipack(ipack *p); void ps_pes(ipack *p); // use with ipack structure, repack size and callback func int64_t ts_demux(int fd_in, int fdv_out,int fda_out,uint16_t pida, uint16_t pidv, int es); void ts2es(int fdin, uint16_t pidv); void insert_pat_pmt( int fdin, int fdout); void change_aspect(int fdin, int fdout, int aspect); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _TS_TRANSFORM_H_*/ dvbstream-20090621.orig/mpegtools/remux.h0000644000175000017500000000574107470507577016726 0ustar markmark/* * mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at marcus@convergence.de, * the project's page is at http://linuxtv.org/dvb/ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ringbuffy.h" #include "ctools.h" #ifndef _REMUX_H_ #define _REMUX_H_ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct video_i{ u32 horizontal_size; u32 vertical_size ; u32 aspect_ratio ; double framerate ; u32 video_format; u32 bit_rate ; u32 comp_bit_rate ; u32 vbv_buffer_size; u32 CSPF ; u32 off; } VideoInfo; typedef struct audio_i{ int layer; u32 bit_rate; u32 frequency; u32 mode; u32 mode_extension; u32 emphasis; u32 framesize; u32 off; } AudioInfo; typedef struct PTS_list_struct{ u32 PTS; int pos; u32 dts; int spos; } PTS_List; typedef struct frame_list_struct{ int type; int pos; u32 FRAME; u32 time; u32 pts; u32 dts; } FRAME_List; typedef struct remux_struct{ ringbuffy vid_buffy; ringbuffy aud_buffy; PTS_List vpts_list[MAX_PTS]; PTS_List apts_list[MAX_PTS]; FRAME_List vframe_list[MAX_FRAME]; FRAME_List aframe_list[MAX_FRAME]; int vptsn; int aptsn; int vframen; int aframen; long apes; long vpes; u32 vframe; u32 aframe; u32 vcframe; u32 acframe; u32 vpts; u32 vdts; u32 apts; u32 vpts_old; u32 apts_old; u32 SCR; u32 apts_off; u32 vpts_off; u32 apts_delay; u32 vpts_delay; u32 dts_delay; AudioInfo audio_info; VideoInfo video_info; int fin; int fout; long int awrite; long int vwrite; long int aread; long int vread; u32 group; u32 groupframe; u32 muxr; int pack_size; u32 time_off; } Remux; enum { NONE, I_FRAME, P_FRAME, B_FRAME, D_FRAME }; void remux(int fin, int fout, int pack_size, int mult); void remux2(int fdin, int fdout); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /*_REMUX_H_*/ dvbstream-20090621.orig/mpegtools/ringbuffy.h0000644000175000017500000000305307470507545017546 0ustar markmark/* Ringbuffer Implementation for gtvscreen Copyright (C) 2000 Marcus Metzler (mocm@metzlerbros.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef RINGBUFFY_H #define RINGBUFFY_H #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define FULL_BUFFER -1000 typedef struct ringbuffy{ int read_pos; int write_pos; int size; char *buffy; } ringbuffy; int ring_init (ringbuffy *rbuf, int size); void ring_destroy(ringbuffy *rbuf); int ring_write(ringbuffy *rbuf, char *data, int count); int ring_read(ringbuffy *rbuf, char *data, int count); int ring_write_file(ringbuffy *rbuf, int fd, int count); int ring_read_file(ringbuffy *rbuf, int fd, int count); int ring_rest(ringbuffy *rbuf); int ring_peek(ringbuffy *rbuf, char *data, int count, long off); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* RINGBUFFY_H */ dvbstream-20090621.orig/mpegtools/ringbuffy.c0000644000175000017500000001052707470507566017550 0ustar markmark/* Ringbuffer Implementation for gtvscreen Copyright (C) 2000 Marcus Metzler (mocm@metzlerbros.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "ringbuffy.h" int ring_init (ringbuffy *rbuf, int size) { if (size > 0){ rbuf->size = size; if( !(rbuf->buffy = (char *) malloc(sizeof(char)*size)) ){ fprintf(stderr,"Not enough memory for ringbuffy\n"); return -1; } } else { fprintf(stderr,"Wrong size for ringbuffy\n"); return -1; } rbuf->read_pos = 0; rbuf->write_pos = 0; return 0; } void ring_destroy(ringbuffy *rbuf) { free(rbuf->buffy); } int ring_write(ringbuffy *rbuf, char *data, int count) { int diff, free, pos, rest; if (count <=0 ) return 0; pos = rbuf->write_pos; rest = rbuf->size - pos; diff = rbuf->read_pos - pos; free = (diff > 0) ? diff-1 : rbuf->size+diff-1; if ( free <= 0 ) return FULL_BUFFER; if ( free < count ) count = free; if (count >= rest){ memcpy (rbuf->buffy+pos, data, rest); if (count - rest) memcpy (rbuf->buffy, data+rest, count - rest); rbuf->write_pos = count - rest; } else { memcpy (rbuf->buffy+pos, data, count); rbuf->write_pos += count; } return count; } int ring_peek(ringbuffy *rbuf, char *data, int count, long off) { int diff, free, pos, rest; if (count <=0 ) return 0; pos = rbuf->read_pos+off; rest = rbuf->size - pos ; diff = rbuf->write_pos - pos; free = (diff >= 0) ? diff : rbuf->size+diff; if ( free <= 0 ) return FULL_BUFFER; if ( free < count ) count = free; if ( count < rest ){ memcpy(data, rbuf->buffy+pos, count); } else { memcpy(data, rbuf->buffy+pos, rest); if ( count - rest) memcpy(data+rest, rbuf->buffy, count - rest); } return count; } int ring_read(ringbuffy *rbuf, char *data, int count) { int diff, free, pos, rest; if (count <=0 ) return 0; pos = rbuf->read_pos; rest = rbuf->size - pos; diff = rbuf->write_pos - pos; free = (diff >= 0) ? diff : rbuf->size+diff; if ( rest <= 0 ) return 0; if ( free < count ) count = free; if ( count < rest ){ memcpy(data, rbuf->buffy+pos, count); rbuf->read_pos += count; } else { memcpy(data, rbuf->buffy+pos, rest); if ( count - rest) memcpy(data+rest, rbuf->buffy, count - rest); rbuf->read_pos = count - rest; } return count; } int ring_write_file(ringbuffy *rbuf, int fd, int count) { int diff, free, pos, rest, rr; if (count <=0 ) return 0; pos = rbuf->write_pos; rest = rbuf->size - pos; diff = rbuf->read_pos - pos; free = (diff > 0) ? diff-1 : rbuf->size+diff-1; if ( rest <= 0 ) return 0; if ( free < count ) count = free; if (count >= rest){ rr = read (fd, rbuf->buffy+pos, rest); if (rr == rest && count - rest) rr += read (fd, rbuf->buffy, count - rest); if (rr >=0) rbuf->write_pos = (pos + rr) % rbuf->size; } else { rr = read (fd, rbuf->buffy+pos, count); if (rr >=0) rbuf->write_pos += rr; } return rr; } int ring_read_file(ringbuffy *rbuf, int fd, int count) { int diff, free, pos, rest, rr; if (count <=0 ) return 0; pos = rbuf->read_pos; rest = rbuf->size - pos; diff = rbuf->write_pos - pos; free = (diff >= 0) ? diff : rbuf->size+diff; if ( free <= 0 ) return FULL_BUFFER; if ( free < count ) count = free; if (count >= rest){ rr = write (fd, rbuf->buffy+pos, rest); if (rr == rest && count - rest) rr += write (fd, rbuf->buffy, count - rest); if (rr >=0) rbuf->read_pos = (pos + rr) % rbuf->size; } else { rr = write (fd, rbuf->buffy+pos, count); if (rr >=0) rbuf->read_pos += rr; } return rr; } int ring_rest(ringbuffy *rbuf){ int diff, free, pos, rest; pos = rbuf->read_pos; rest = rbuf->size - pos; diff = rbuf->write_pos - pos; free = (diff >= 0) ? diff : rbuf->size+diff; return free; } dvbstream-20090621.orig/mpegtools/ctools.h0000644000175000017500000002206607470507561017061 0ustar markmark/* * mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at marcus@convergence.de, * the project's page is at http://linuxtv.org/dvb/ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ringbuffy.h" #include "transform.h" #ifndef _CTOOLS_H_ #define _CTOOLS_H_ #define VIDEO_MODE_PAL 0 #define VIDEO_MODE_NTSC 1 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; enum {PS_STREAM, TS_STREAM, PES_STREAM}; enum {pDUNNO, pPAL, pNTSC}; u32 trans_pts_dts(u8 *pts); /* PES */ #define PROG_STREAM_MAP 0xBC #ifndef PRIVATE_STREAM1 #define PRIVATE_STREAM1 0xBD #endif #define PADDING_STREAM 0xBE #ifndef PRIVATE_STREAM2 #define PRIVATE_STREAM2 0xBF #endif #define AUDIO_STREAM_S 0xC0 #define AUDIO_STREAM_E 0xDF #define VIDEO_STREAM_S 0xE0 #define VIDEO_STREAM_E 0xEF #define ECM_STREAM 0xF0 #define EMM_STREAM 0xF1 #define DSM_CC_STREAM 0xF2 #define ISO13522_STREAM 0xF3 #define PROG_STREAM_DIR 0xFF #define BUFFYSIZE 10*MAX_PLENGTH #define MAX_PTS 8192 #define MAX_FRAME 8192 #define MAX_PACK_L 4096 #define PS_HEADER_L1 14 #define PS_HEADER_L2 (PS_HEADER_L1+18) #define MAX_H_SIZE (PES_H_MIN + PS_HEADER_L1 + 5) #define PES_MIN 7 #define PES_H_MIN 9 //flags1 #define FLAGS 0x40 #define SCRAMBLE_FLAGS 0x30 #define PRIORITY_FLAG 0x08 #define DATA_ALIGN_FLAG 0x04 #define COPYRIGHT_FLAG 0x02 #define ORIGINAL_FLAG 0x01 //flags2 #define PTS_DTS_FLAGS 0xC0 #define ESCR_FLAG 0x20 #define ES_RATE_FLAG 0x10 #define DSM_TRICK_FLAG 0x08 #define ADD_CPY_FLAG 0x04 #define PES_CRC_FLAG 0x02 #define PES_EXT_FLAG 0x01 //pts_dts flags #define PTS_ONLY 0x80 #define PTS_DTS 0xC0 //private flags #define PRIVATE_DATA 0x80 #define HEADER_FIELD 0x40 #define PACK_SEQ_CTR 0x20 #define P_STD_BUFFER 0x10 #define PES_EXT_FLAG2 0x01 #define MPEG1_2_ID 0x40 #define STFF_LNGTH_MASK 0x3F typedef struct pes_packet_{ u8 stream_id; u8 llength[2]; uint32_t length; u8 flags1; u8 flags2; u8 pes_hlength; u8 pts[5]; u8 dts[5]; u8 escr[6]; u8 es_rate[3]; u8 trick; u8 add_cpy; u8 prev_pes_crc[2]; u8 priv_flags; u8 pes_priv_data[16]; u8 pack_field_length; u8 *pack_header; u8 pck_sqnc_cntr; u8 org_stuff_length; u8 p_std[2]; u8 pes_ext_lngth; u8 *pes_ext; u8 *pes_pckt_data; int padding; int mpeg; int mpeg1_pad; u8 *mpeg1_headr; u8 stuffing; } pes_packet; void init_pes(pes_packet *p); void kill_pes(pes_packet *p); void setlength_pes(pes_packet *p); void nlength_pes(pes_packet *p); int cwrite_pes(u8 *buf, pes_packet *p, long length); void write_pes(int fd, pes_packet *p); int read_pes(int f, pes_packet *p); void cread_pes(char *buf, pes_packet *p); /* Transport Stream */ #define TS_SIZE 188 #define TRANS_ERROR 0x80 #define PAY_START 0x40 #define TRANS_PRIO 0x20 #define PID_MASK_HI 0x1F //flags #define TRANS_SCRMBL1 0x80 #define TRANS_SCRMBL2 0x40 #define ADAPT_FIELD 0x20 #define PAYLOAD 0x10 #define COUNT_MASK 0x0F // adaptation flags #define DISCON_IND 0x80 #define RAND_ACC_IND 0x40 #define ES_PRI_IND 0x20 #define PCR_FLAG 0x10 #define OPCR_FLAG 0x08 #define SPLICE_FLAG 0x04 #define TRANS_PRIV 0x02 #define ADAP_EXT_FLAG 0x01 // adaptation extension flags #define LTW_FLAG 0x80 #define PIECE_RATE 0x40 #define SEAM_SPLICE 0x20 typedef struct ts_packet_{ u8 pid[2]; u8 flags; u8 count; u8 data[184]; u8 adapt_length; u8 adapt_flags; u8 pcr[6]; u8 opcr[6]; u8 splice_count; u8 priv_dat_len; u8 *priv_dat; u8 adapt_ext_len; u8 adapt_eflags; u8 ltw[2]; u8 piece_rate[3]; u8 dts[5]; int rest; u8 stuffing; } ts_packet; void init_ts(ts_packet *p); void kill_ts(ts_packet *p); unsigned short pid_ts(ts_packet *p); int cwrite_ts(u8 *buf, ts_packet *p, long length); void write_ts(int fd, ts_packet *p); int read_ts(int f, ts_packet *p); void cread_ts (char *buf, ts_packet *p, long length); /* Program Stream */ #define PACK_STUFF_MASK 0x07 #define FIXED_FLAG 0x02 #define CSPS_FLAG 0x01 #define SAUDIO_LOCK_FLAG 0x80 #define SVIDEO_LOCK_FLAG 0x40 #define PS_MAX 200 typedef struct ps_packet_{ u8 scr[6]; u8 mux_rate[3]; u8 stuff_length; u8 *data; u8 sheader_llength[2]; int sheader_length; u8 rate_bound[3]; u8 audio_bound; u8 video_bound; u8 reserved; int npes; int mpeg; } ps_packet; void init_ps(ps_packet *p); void kill_ps(ps_packet *p); void setlength_ps(ps_packet *p); u32 scr_base_ps(ps_packet *p); u16 scr_ext_ps(ps_packet *p); int mux_ps(ps_packet *p); int rate_ps(ps_packet *p); int cwrite_ps(u8 *buf, ps_packet *p, long length); void write_ps(int fd, ps_packet *p); int read_ps (int f, ps_packet *p); void cread_ps (char *buf, ps_packet *p, long length); #define MAX_PLENGTH 0xFFFF typedef struct sectionstruct { int id; int length; int found; u8 payload[4096+3]; } section; typedef u32 tflags; #define MAXFILT 32 #define MASKL 16 typedef struct trans_struct { int found; u8 packet[188]; u16 pid[MAXFILT]; u8 mask[MAXFILT*MASKL]; u8 filt[MAXFILT*MASKL]; u8 transbuf[MAXFILT*188]; int transcount[MAXFILT]; section sec[MAXFILT]; tflags is_full; tflags pes_start; tflags pes_started; tflags pes; tflags set; } trans; void init_trans(trans *p); int set_trans_filt(trans *p, int filtn, u16 pid, u8 *mask, u8 *filt, int pes); void clear_trans_filt(trans *p,int filtn); int filt_is_set(trans *p, int filtn); int pes_is_set(trans *p, int filtn); int pes_is_started(trans *p, int filtn); int pes_is_start(trans *p, int filtn); int filt_is_ready(trans *p,int filtn); void trans_filt(u8 *buf, int count, trans *p); void filter(trans *p); void pes_filter(trans *p, int filtn, int off); void sec_filter(trans *p, int filtn, int off); int get_filt_buf(trans *p, int filtn,u8 **buf); section *get_filt_sec(trans *p, int filtn); typedef struct a2pstruct{ int type; int fd; int found; int length; int headr; int plength; u8 cid; u8 flags; u8 abuf[MAX_PLENGTH]; int alength; u8 vbuf[MAX_PLENGTH]; int vlength; u8 last_av_pts[4]; u8 av_pts[4]; u8 scr[4]; u8 pid0; u8 pid1; u8 pidv; u8 pida; } a2p; void get_pespts(u8 *av_pts,u8 *pts); void init_a2p(a2p *p); void av_pes_to_pes(u8 *buf,int count, a2p *p); int w_pesh(u8 id,int length ,u8 *pts, u8 *obuf); int w_tsh(u8 id,int length ,u8 *pts, u8 *obuf,a2p *p,int startpes); void pts2pts(u8 *av_pts, u8 *pts); void write_ps_headr(ps_packet *p,u8 *pts,int fd); typedef struct p2t_s{ u8 pes[TS_SIZE]; u8 counter; long int pos; int frags; void (*t_out)(u8 const *buf); } p2t_t; void twrite(u8 const *buf); void init_p2t(p2t_t *p, void (*fkt)(u8 const *buf)); long int find_pes_header(u8 const *buf, long int length, int *frags); void pes_to_ts( u8 const *buf, long int length, u16 pid, p2t_t *p); void p_to_t( u8 const *buf, long int length, u16 pid, u8 *counter, void (*ts_write)(u8 const *)); int write_pes_header(u8 id,int length , long PTS, u8 *obuf, int stuffing); int write_ps_header(uint8_t *buf, uint32_t SCR, long muxr, uint8_t audio_bound, uint8_t fixed, uint8_t CSPS, uint8_t audio_lock, uint8_t video_lock, uint8_t video_bound, uint8_t stream1, uint8_t buffer1_scale, uint32_t buffer1_size, uint8_t stream2, uint8_t buffer2_scale, uint32_t buffer2_size); void split_mpg(char *name, uint64_t size); void cut_mpg(char *name, uint64_t size); int http_open (char *url); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /*_CTOOLS_H_*/ dvbstream-20090621.orig/mpegtools/transform.c0000644000175000017500000013020607470507576017566 0ustar markmark/* * mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at marcus@convergence.de, * the project's page is at http://linuxtv.org/dvb/ */ #include "transform.h" #include #include #include "ctools.h" static uint8_t tspid0[TS_SIZE] = { 0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xb0, 0x11, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x00, 0x01, 0xe4, 0x00, 0x2a, 0xd6, 0x1a, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static uint8_t tspid1[TS_SIZE] = { 0x47, 0x44, 0x00, 0x10, 0x00, 0x02, 0xb0, 0x1c, 0x00, 0x01, 0xcb, 0x00, 0x00, 0xe0, 0xa0, 0xf0, 0x05, 0x48, 0x03, 0x01, 0x00, 0x00, 0x02, 0xe0, 0xa0, 0xf0, 0x00, 0x03, 0xe0, 0x50, 0xf0, 0x00, 0xae, 0xea, 0x4e, 0x48, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; uint32_t trans_pts_dts(uint8_t *pts) { uint32_t wts; wts = (((pts[0] & 0x06) << 4) | ((pts[1] & 0xFC) >> 2)) << 24; wts |= (((pts[1] & 0x03) << 6) | ((pts[2] & 0xFC) >> 2)) << 16; wts |= (((pts[2] & 0x02) << 6) | ((pts[3] & 0xFE) >> 1)) << 8; wts |= (((pts[3] & 0x01) << 7) | ((pts[4] & 0xFE) >> 1)); return wts; } void get_pespts(uint8_t *av_pts,uint8_t *pts) { pts[0] = 0x21 | ((av_pts[0] & 0xC0) >>5); pts[1] = ((av_pts[0] & 0x3F) << 2) | ((av_pts[1] & 0xC0) >> 6); pts[2] = 0x01 | ((av_pts[1] & 0x3F) << 2) | ((av_pts[2] & 0x80) >> 6); pts[3] = ((av_pts[2] & 0x7F) << 1) | ((av_pts[3] & 0x80) >> 7); pts[4] = 0x01 | ((av_pts[3] & 0x7F) << 1); } uint16_t get_pid(uint8_t *pid) { uint16_t pp = 0; pp = (pid[0] & PID_MASK_HI)<<8; pp |= pid[1]; return pp; } int write_ts_header(uint16_t pid, uint8_t *counter, int pes_start, uint8_t *buf, uint8_t length) { int i; int c = 0; int fill; uint8_t tshead[4] = { 0x47, 0x00, 0x00, 0x10}; fill = TS_SIZE-4-length; if (pes_start) tshead[1] = 0x40; if (fill) tshead[3] = 0x30; tshead[1] |= (uint8_t)((pid & 0x1F00) >> 8); tshead[2] |= (uint8_t)(pid & 0x00FF); tshead[3] |= ((*counter)++ & 0x0F) ; memcpy(buf,tshead,4); c+=4; if (fill){ buf[4] = fill-1; c++; if (fill >1){ buf[5] = 0x00; c++; } for ( i = 6; i < fill+4; i++){ buf[i] = 0xFF; c++; } } return c; } int write_pes_header(uint8_t id,int length , long PTS, uint8_t *obuf, int stuffing) { uint8_t le[2]; uint8_t dummy[3]; uint8_t *pts; uint8_t ppts[5]; long lpts; int c; uint8_t headr[3] = {0x00, 0x00, 0x01}; lpts = htonl(PTS); pts = (uint8_t *) &lpts; get_pespts(pts,ppts); c = 0; memcpy(obuf+c,headr,3); c += 3; memcpy(obuf+c,&id,1); c++; le[0] = 0; le[1] = 0; length -= 6+stuffing; le[0] |= ((uint8_t)(length >> 8) & 0xFF); le[1] |= ((uint8_t)(length) & 0xFF); memcpy(obuf+c,le,2); c += 2; if (id == PADDING_STREAM){ memset(obuf+c,0xff,length); c+= length; return c; } dummy[0] = 0x80; dummy[1] = 0; dummy[2] = 0; if (PTS){ dummy[1] |= PTS_ONLY; dummy[2] = 5+stuffing; } memcpy(obuf+c,dummy,3); c += 3; memset(obuf+c,0xFF,stuffing); if (PTS){ memcpy(obuf+c,ppts,5); c += 5; } return c; } void init_p2p(p2p *p, void (*func)(uint8_t *buf, int count, p2p *p), int repack){ p->found = 0; p->cid = 0; p->mpeg = 0; memset(p->buf,0,MMAX_PLENGTH); p->done = 0; p->fd1 = -1; p->func = func; p->bigend_repack = 0; p->repack = 0; if ( repack < MAX_PLENGTH && repack > 265 ){ p->repack = repack-6; p->bigend_repack = (uint16_t)htons((short) ((repack-6) & 0xFFFF)); } else { fprintf(stderr, "Repack size %d is out of range\n",repack); exit(1); } } void pes_repack(p2p *p) { int count = 0; int repack = p->repack; int rest = p->plength; uint8_t buf[MAX_PLENGTH]; int bfill = 0; int diff; uint16_t length; if (rest < 0) { fprintf(stderr,"Error in repack\n"); return; } if (!repack){ fprintf(stderr,"forgot to set repack size\n"); return; } if (p->plength == repack){ memcpy(p->buf+4,(char *)&p->bigend_repack,2); p->func(p->buf, repack+6, p); return; } buf[0] = 0x00; buf[1] = 0x00; buf[2] = 0x01; buf[3] = p->cid; memcpy(buf+4,(char *)&p->bigend_repack,2); memset(buf+6,0,MAX_PLENGTH-6); if (p->mpeg == 2){ if ( rest > repack){ memcpy(p->buf+4,(char *)&p->bigend_repack,2); p->func(p->buf, repack+6, p); count += repack+6; rest -= repack; } else { memcpy(buf,p->buf,9+p->hlength); bfill = p->hlength; count += 9+p->hlength; rest -= p->hlength+3; } while (rest >= repack-3){ memset(buf+6,0,MAX_PLENGTH-6); buf[6] = 0x80; buf[7] = 0x00; buf[8] = 0x00; memcpy(buf+9,p->buf+count,repack-3); rest -= repack-3; count += repack-3; p->func(buf, repack+6, p); } if (rest){ diff = repack - 3 - rest - bfill; if (!bfill){ buf[6] = 0x80; buf[7] = 0x00; buf[8] = 0x00; } if ( diff < PES_MIN){ length = rest+ diff + bfill+3; buf[4] = (uint8_t)((length & 0xFF00) >> 8); buf[5] = (uint8_t)(length & 0x00FF); buf[8] = (uint8_t)(bfill+diff); memset(buf+9+bfill,0xFF,diff); memcpy(buf+9+bfill+diff,p->buf+count,rest); } else { length = rest+ bfill+3; buf[4] = (uint8_t)((length & 0xFF00) >> 8); buf[5] = (uint8_t)(length & 0x00FF); memcpy(buf+9+bfill,p->buf+count,rest); bfill += rest+9; write_pes_header( PADDING_STREAM, diff, 0, buf+bfill, 0); } p->func(buf, repack+6, p); } } if (p->mpeg == 1){ if ( rest > repack){ memcpy(p->buf+4,(char *)&p->bigend_repack,2); p->func(p->buf, repack+6, p); count += repack+6; rest -= repack; } else { memcpy(buf,p->buf,6+p->hlength); bfill = p->hlength; count += 6; rest -= p->hlength; } while (rest >= repack-1){ memset(buf+6,0,MAX_PLENGTH-6); buf[6] = 0x0F; memcpy(buf+7,p->buf+count,repack-1); rest -= repack-1; count += repack-1; p->func(buf, repack+6, p); } if (rest){ diff = repack - 1 - rest - bfill; if ( diff < PES_MIN){ length = rest+ diff + bfill+1; buf[4] = (uint8_t)((length & 0xFF00) >> 8); buf[5] = (uint8_t)(length & 0x00FF); memset(buf+6,0xFF,diff); if (!bfill){ buf[6+diff] = 0x0F; } memcpy(buf+7+diff,p->buf+count,rest+bfill); } else { length = rest+ bfill+1; buf[4] = (uint8_t)((length & 0xFF00) >> 8); buf[5] = (uint8_t)(length & 0x00FF); if (!bfill){ buf[6] = 0x0F; memcpy(buf+7,p->buf+count,rest); bfill = rest+7; } else { memcpy(buf+6,p->buf+count,rest+bfill); bfill += rest+6; } write_pes_header( PADDING_STREAM, diff, 0, buf+bfill, 0); } p->func(buf, repack+6, p); } } } void pes_filt(p2p *p) { int factor = p->mpeg-1; if ( p->cid == p->filter) { if (p->es) write(p->fd1,p->buf+p->hlength+6+3*factor, p->plength-p->hlength-3*factor); else write(p->fd1,p->buf,p->plength+6); } } #define SIZE 4096 void extract_from_pes(int fdin, int fdout, uint8_t id, int es) { p2p p; int count = 1; uint8_t buf[SIZE]; init_p2p(&p, NULL, 2048); p.fd1 = fdout; p.filter = id; p.es = es; while (count > 0){ count = read(fdin,buf,SIZE); get_pes(buf,count,&p,pes_filt); } } void pes_dfilt(p2p *p) { int factor = p->mpeg-1; int fd =0; int type = NOPES; switch ( p->cid ) { case AUDIO_STREAM_S ... AUDIO_STREAM_E: fd = p->fd1; type = AUDIO; break; case VIDEO_STREAM_S ... VIDEO_STREAM_E: fd = p->fd2; type = VIDEO; break; } if (p->es && !p->startv && type == VIDEO){ int found = 0; int c = 6+p->hlength+3*factor; if ( p->flag2 & PTS_DTS ) p->vpts = ntohl(trans_pts_dts(p->pts)); while ( !found && c+3 < p->plength+6 ){ if ( p->buf[c] == 0x00 && p->buf[c+1] == 0x00 && p->buf[c+2] == 0x01 && p->buf[c+3] == 0xb3) found = 1; else c++; } if (found){ p->startv = 1; write(fd, p->buf+c, p->plength+6-c); } fd = 0; } if ( p->es && !p->starta && type == AUDIO){ int found = 0; int c = 6+p->hlength+3*factor; if ( p->flag2 & PTS_DTS ) p->apts = ntohl(trans_pts_dts(p->pts)); if (p->startv) while ( !found && c+1 < p->plength+6){ if ( p->buf[c] == 0xFF && (p->buf[c+1] & 0xF8) == 0xF8) found = 1; else c++; } if (found){ p->starta = 1; write(fd, p->buf+c, p->plength+6-c); } fd = 0; } if (fd){ if (p->es) write(fd,p->buf+p->hlength+6+3*factor, p->plength-p->hlength-3*factor); else write(fd,p->buf,p->plength+6); } } int64_t pes_dmx( int fdin, int fdouta, int fdoutv, int es) { p2p p; int count = 1; uint8_t buf[SIZE]; uint64_t length = 0; uint64_t l = 0; int verb = 0; init_p2p(&p, NULL, 2048); p.fd1 = fdouta; p.fd2 = fdoutv; p.es = es; p.startv = 0; p.starta = 0; p.apts=-1; p.vpts=-1; if (fdin != STDIN_FILENO) verb = 1; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } while (count > 0){ count = read(fdin,buf,SIZE); l += count; if (verb) fprintf(stderr,"Demuxing %2.2f %%\r", 100.*l/length); get_pes(buf,count,&p,pes_dfilt); } return (int64_t)p.vpts - (int64_t)p.apts; } static void pes_in_ts(p2p *p) { int l, pes_start; uint8_t obuf[TS_SIZE]; long int c = 0; int length = p->plength+6; uint16_t pid; uint8_t *counter; pes_start = 1; switch ( p->cid ) { case AUDIO_STREAM_S ... AUDIO_STREAM_E: pid = p->pida; counter = &p->acounter; break; case VIDEO_STREAM_S ... VIDEO_STREAM_E: pid = p->pidv; counter = &p->acounter; tspid0[3] |= (p->count0++) & 0x0F ; tspid1[3] |= (p->count1++) & 0x0F ; tspid1[24] = p->pidv; tspid1[23] |= (p->pidv >> 8) & 0x3F; tspid1[29] = p->pida; tspid1[28] |= (p->pida >> 8) & 0x3F; p->func(tspid0,188,p); p->func(tspid1,188,p); break; default: return; } while ( c < length ){ memset(obuf,0,TS_SIZE); if (length - c >= TS_SIZE-4){ l = write_ts_header(pid, counter, pes_start , obuf, TS_SIZE-4); memcpy(obuf+l, p->buf+c, TS_SIZE-l); c += TS_SIZE-l; } else { l = write_ts_header(pid, counter, pes_start , obuf, length-c); memcpy(obuf+l, p->buf+c, TS_SIZE-l); c = length; } p->func(obuf,188,p); pes_start = 0; } } void pes_to_ts2( int fdin, int fdout, uint16_t pida, uint16_t pidv) { p2p p; int count = 1; uint8_t buf[SIZE]; uint64_t length = 0; uint64_t l = 0; int verb = 0; init_p2p(&p, NULL, 2048); p.fd1 = fdout; p.pida = pida; p.pidv = pidv; p.acounter = 0; p.vcounter = 0; p.count1 = 0; p.count0 = 0; if (fdin != STDIN_FILENO) verb = 1; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } while (count > 0){ count = read(fdin,buf,SIZE); l += count; if (verb) fprintf(stderr,"Writing TS %2.2f %%\r", 100.*l/length); get_pes(buf,count,&p,pes_in_ts); } } void write_out(uint8_t *buf, int count,void *p) { write(STDOUT_FILENO, buf, count); } #define IN_SIZE TS_SIZE*10 #define IPACKS 2048 void find_avpids(int fd, uint16_t *vpid, uint16_t *apid) { uint8_t buf[IN_SIZE]; int count; int i; int off =0; while ( *apid == 0 || *vpid == 0){ count = read(fd, buf, IN_SIZE); for (i = 0; i < count-7; i++){ if (buf[i] == 0x47){ if (buf[i+1] & 0x40){ off = 0; if ( buf[3+i] & 0x20)//adapt field? off = buf[4+i] + 1; switch(buf[i+7+off]){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: *vpid = get_pid(buf+i+1); break; case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: *apid = get_pid(buf+i+1); break; } } i += 187; } if (*apid != 0 && *vpid != 0) break; } } } void find_bavpids(uint8_t *buf, int count, uint16_t *vpid, uint16_t *apid) { int i; int founda = 0; int foundb = 0; int off = 0; *vpid = 0; *apid = 0; for (i = 0; i < count-7; i++){ if (buf[i] == 0x47){ if ((buf[i+1] & 0xF0) == 0x40){ off = 0; if ( buf[3+i] & 0x20) // adaptation field? off = buf[4+i] + 1; if (buf[off+i+4] == 0x00 && buf[off+i+5] == 0x00 && buf[off+i+6] == 0x01){ switch(buf[off+i+7]){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: *vpid = get_pid(buf+i+1); foundb=1; break; case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: *apid = get_pid(buf+i+1); founda=1; break; } } } i += 187; } if (founda && foundb) break; } } void ts_to_pes( int fdin, uint16_t pida, uint16_t pidv, int ps) { uint8_t buf[IN_SIZE]; uint8_t mbuf[TS_SIZE]; int i; int count = 1; uint16_t pid; uint16_t dummy; ipack pa, pv; ipack *p; if (fdin != STDIN_FILENO && (!pida || !pidv)) find_avpids(fdin, &pidv, &pida); init_ipack(&pa, IPACKS,write_out, ps); init_ipack(&pv, IPACKS,write_out, ps); if ((count = read(fdin,mbuf,TS_SIZE))<0) perror("reading"); for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); return; } else { memcpy(buf,mbuf+i,TS_SIZE-i); if ((count = read(fdin,mbuf,i))<0) perror("reading"); memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } count = 1; while (count > 0){ if ((count = read(fdin,buf+i,IN_SIZE-i))<0) perror("reading"); if (!pidv){ find_bavpids(buf+i, IN_SIZE-i, &pidv, &dummy); if (pidv) fprintf(stderr, "vpid %d (0x%02x)\n", pidv,pidv); } if (!pida){ find_bavpids(buf+i, IN_SIZE-i, &dummy, &pida); if (pida) fprintf(stderr, "apid %d (0x%02x)\n", pida,pida); } for( i = 0; i < count; i+= TS_SIZE){ uint8_t off = 0; if ( count - i < TS_SIZE) break; pid = get_pid(buf+i+1); if (!(buf[3+i]&0x10)) // no payload? continue; if (pid == pidv){ p = &pv; } else { if (pid == pida){ p = &pa; } else continue; } if ( buf[1+i]&0x40) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; send_ipack(p); reset_ipack(p); } } if ( buf[3+i] & 0x20) { // adaptation field? off = buf[4+i] + 1; } instant_repack(buf+4+off+i, TS_SIZE-4-off, p); } i = 0; } } #define INN_SIZE 2*IN_SIZE void insert_pat_pmt( int fdin, int fdout) { uint8_t buf[INN_SIZE]; uint8_t mbuf[TS_SIZE]; int i; int count = 1; uint16_t pida = 0; uint16_t pidv = 0; int written,c; uint8_t c0 = 0; uint8_t c1 = 0; find_avpids(fdin, &pidv, &pida); count = read(fdin,mbuf,TS_SIZE); for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); return; } else { memcpy(buf,mbuf+i,TS_SIZE-i); count = read(fdin,mbuf,i); memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } count = 1; while (count > 0){ tspid1[24] = pidv; tspid1[23] |= (pidv >> 8) & 0x3F; tspid1[29] = pida; tspid1[28] |= (pida >> 8) & 0x3F; write(fdout,tspid0,188); write(fdout,tspid1,188); count = read(fdin,buf+i,INN_SIZE-i); written = 0; while (written < IN_SIZE){ c = write(fdout,buf,INN_SIZE); if (c>0) written += c; } tspid0[3] |= (c0++) & 0x0F ; tspid1[3] |= (c1++) & 0x0F ; i=0; } } void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)) { int l; unsigned short *pl; int c=0; uint8_t headr[3] = { 0x00, 0x00, 0x01} ; while (c < count && (p->mpeg == 0 || (p->mpeg == 1 && p->found < 7) || (p->mpeg == 2 && p->found < 9)) && (p->found < 5 || !p->done)){ switch ( p->found ){ case 0: case 1: if (buf[c] == 0x00) p->found++; else p->found = 0; c++; break; case 2: if (buf[c] == 0x01) p->found++; else if (buf[c] == 0){ p->found = 2; } else p->found = 0; c++; break; case 3: p->cid = 0; switch (buf[c]){ case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: p->done = 1; case PRIVATE_STREAM1: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case AUDIO_STREAM_S ... AUDIO_STREAM_E: p->found++; p->cid = buf[c]; c++; break; default: p->found = 0; break; } break; case 4: if (count-c > 1){ pl = (unsigned short *) (buf+c); p->plength = ntohs(*pl); p->plen[0] = buf[c]; c++; p->plen[1] = buf[c]; c++; p->found+=2; } else { p->plen[0] = buf[c]; p->found++; return; } break; case 5: p->plen[1] = buf[c]; c++; pl = (unsigned short *) p->plen; p->plength = ntohs(*pl); p->found++; break; case 6: if (!p->done){ p->flag1 = buf[c]; c++; p->found++; if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; else { p->hlength = 0; p->which = 0; p->mpeg = 1; p->flag2 = 0; } } break; case 7: if ( !p->done && p->mpeg == 2){ p->flag2 = buf[c]; c++; p->found++; } break; case 8: if ( !p->done && p->mpeg == 2){ p->hlength = buf[c]; c++; p->found++; } break; default: break; } } if (!p->plength) p->plength = MMAX_PLENGTH-6; if ( p->done || ((p->mpeg == 2 && p->found >= 9) || (p->mpeg == 1 && p->found >= 7)) ){ switch (p->cid){ case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case PRIVATE_STREAM1: memcpy(p->buf, headr, 3); p->buf[3] = p->cid; memcpy(p->buf+4,p->plen,2); if (p->mpeg == 2 && p->found == 9){ p->buf[6] = p->flag1; p->buf[7] = p->flag2; p->buf[8] = p->hlength; } if (p->mpeg == 1 && p->found == 7){ p->buf[6] = p->flag1; } if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && p->found < 14){ while (c < count && p->found < 14){ p->pts[p->found-9] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; } if (c == count) return; } if (p->mpeg == 1 && p->which < 2000){ if (p->found == 7) { p->check = p->flag1; p->hlength = 1; } while (!p->which && c < count && p->check == 0xFF){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; } if ( c == count) return; if ( (p->check & 0xC0) == 0x40 && !p->which){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 1; if ( c == count) return; p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return; } if (p->which == 1){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return; } if ( (p->check & 0x30) && p->check != 0xFF){ p->flag2 = (p->check & 0xF0) << 2; p->pts[0] = p->check; p->which = 3; } if ( c == count) return; if (p->which > 2){ if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY){ while (c < count && p->which < 7){ p->pts[p->which-2] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->which++; p->hlength++; } if ( c == count) return; } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS){ while (c < count && p->which< 12){ if (p->which< 7) p->pts[p->which -2] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->which++; p->hlength++; } if ( c == count) return; } p->which = 2000; } } while (c < count && p->found < p->plength+6){ l = count -c; if (l+p->found > p->plength+6) l = p->plength+6-p->found; memcpy(p->buf+p->found, buf+c, l); p->found += l; c += l; } if(p->found == p->plength+6) func(p); break; } if ( p->done ){ if( p->found + count - c < p->plength+6){ p->found += count-c; c = count; } else { c += p->plength+6 - p->found; p->found = p->plength+6; } } if (p->plength && p->found == p->plength+6) { p->found = 0; p->done = 0; p->plength = 0; memset(p->buf, 0, MAX_PLENGTH); if (c < count) get_pes(buf+c, count-c, p, func); } } return; } void setup_pes2ts( p2p *p, uint32_t pida, uint32_t pidv, void (*ts_write)(uint8_t *buf, int count, p2p *p)) { init_p2p( p, ts_write, 2048); p->pida = pida; p->pidv = pidv; p->acounter = 0; p->vcounter = 0; p->count1 = 0; p->count0 = 0; } void kpes_to_ts( p2p *p,uint8_t *buf ,int count ) { get_pes(buf,count, p,pes_in_ts); } void setup_ts2pes( p2p *pa, p2p *pv, uint32_t pida, uint32_t pidv, void (*pes_write)(uint8_t *buf, int count, p2p *p)) { init_p2p( pa, pes_write, 2048); init_p2p( pv, pes_write, 2048); pa->pid = pida; pv->pid = pidv; } void kts_to_pes( p2p *p, uint8_t *buf) // don't need count (=188) { uint8_t off = 0; uint16_t pid = 0; if (!(buf[3]&PAYLOAD)) // no payload? return; pid = get_pid(buf+1); if (pid != p->pid) return; if ( buf[1]&PAY_START) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; pes_repack(p); } } if ( buf[3] & ADAPT_FIELD) { // adaptation field? off = buf[4] + 1; if (off+4 > 187) return; } get_pes(buf+4+off, TS_SIZE-4-off, p , pes_repack); } // instant repack void reset_ipack(ipack *p) { p->found = 0; p->cid = 0; p->plength = 0; p->flag1 = 0; p->flag2 = 0; p->hlength = 0; p->mpeg = 0; p->check = 0; p->which = 0; p->done = 0; p->count = 0; p->size = p->size_orig; } void init_ipack(ipack *p, int size, void (*func)(uint8_t *buf, int size, void *priv), int ps) { if ( !(p->buf = malloc(size)) ){ fprintf(stderr,"Couldn't allocate memory for ipack\n"); exit(1); } p->ps = ps; p->size_orig = size; p->func = func; reset_ipack(p); p->has_ai = 0; p->has_vi = 0; p->start = 0; } void free_ipack(ipack * p) { if (p->buf) free(p->buf); } int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) { uint8_t *headr; int found = 0; int sw; int form = -1; int c = 0; while (found < 4 && c+4 < count){ uint8_t *b; b = mbuf+c; if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 && b[3] == 0xb3) found = 4; else { c++; } } if (! found) return -1; c += 4; if (c+12 >= count) return -1; headr = mbuf+c; vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); sw = (int)((headr[3]&0xF0) >> 4) ; switch( sw ){ case 1: if (pr) fprintf(stderr,"Videostream: ASPECT: 1:1"); vi->aspect_ratio = 100; break; case 2: if (pr) fprintf(stderr,"Videostream: ASPECT: 4:3"); vi->aspect_ratio = 133; break; case 3: if (pr) fprintf(stderr,"Videostream: ASPECT: 16:9"); vi->aspect_ratio = 177; break; case 4: if (pr) fprintf(stderr,"Videostream: ASPECT: 2.21:1"); vi->aspect_ratio = 221; break; case 5 ... 15: if (pr) fprintf(stderr,"Videostream: ASPECT: reserved"); vi->aspect_ratio = 0; break; default: vi->aspect_ratio = 0; return -1; } if (pr) fprintf(stderr," Size = %dx%d",vi->horizontal_size, vi->vertical_size); sw = (int)(headr[3]&0x0F); switch ( sw ) { case 1: if (pr) fprintf(stderr," FRate: 23.976 fps"); vi->framerate = 24000/1001.; form = -1; break; case 2: if (pr) fprintf(stderr," FRate: 24 fps"); vi->framerate = 24; form = -1; break; case 3: if (pr) fprintf(stderr," FRate: 25 fps"); vi->framerate = 25; form = VIDEO_MODE_PAL; break; case 4: if (pr) fprintf(stderr," FRate: 29.97 fps"); vi->framerate = 30000/1001.; form = VIDEO_MODE_NTSC; break; case 5: if (pr) fprintf(stderr," FRate: 30 fps"); vi->framerate = 30; form = VIDEO_MODE_NTSC; break; case 6: if (pr) fprintf(stderr," FRate: 50 fps"); vi->framerate = 50; form = VIDEO_MODE_PAL; break; case 7: if (pr) fprintf(stderr," FRate: 60 fps"); vi->framerate = 60; form = VIDEO_MODE_NTSC; break; } vi->bit_rate = 400*(((headr[4] << 10) & 0x0003FC00UL) | ((headr[5] << 2) & 0x000003FCUL) | (((headr[6] & 0xC0) >> 6) & 0x00000003UL)); if (pr){ fprintf(stderr," BRate: %.2f Mbit/s",(vi->bit_rate)/1000000.); fprintf(stderr,"\n"); } vi->video_format = form; vi->off = c-4; return c-4; } extern unsigned int bitrates[3][16]; extern uint32_t freq[4]; int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) { uint8_t *headr; int found = 0; int c = 0; int fr =0; while (!found && c < count){ uint8_t *b = mbuf+c; if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) found = 1; else { c++; } } if (!found) return -1; if (c+3 >= count) return -1; headr = mbuf+c; ai->layer = (headr[1] & 0x06) >> 1; if (pr) fprintf(stderr,"Audiostream: Layer: %d", 4-ai->layer); ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; if (pr){ if (ai->bit_rate == 0) fprintf (stderr," Bit rate: free"); else if (ai->bit_rate == 0xf) fprintf (stderr," BRate: reserved"); else fprintf (stderr," BRate: %d kb/s", ai->bit_rate/1000); } fr = (headr[2] & 0x0c ) >> 2; ai->frequency = freq[fr]*100; if (pr){ if (ai->frequency == 3) fprintf (stderr, " Freq: reserved\n"); else fprintf (stderr," Freq: %2.1f kHz\n", ai->frequency/1000.); } ai->off = c; return c; } unsigned int ac3_bitrates[32] = {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, 0,0,0,0,0,0,0,0,0,0,0,0,0}; uint32_t ac3_freq[4] = {480, 441, 320, 0}; uint32_t ac3_frames[3][32] = {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr) { uint8_t *headr; int found = 0; int c = 0; uint8_t frame; int fr = 0; while ( !found && c < count){ uint8_t *b = mbuf+c; if ( b[0] == 0x0b && b[1] == 0x77 ) found = 1; else { c++; } } if (!found){ return -1; } ai->off = c; if (c+5 >= count) return -1; ai->layer = 0; // 0 for AC3 headr = mbuf+c+2; frame = (headr[2]&0x3f); ai->bit_rate = ac3_bitrates[frame>>1]*1000; if (pr) fprintf (stderr," BRate: %d kb/s", ai->bit_rate/1000); fr = (headr[2] & 0xc0 ) >> 6; ai->frequency = freq[fr]*100; if (pr) fprintf (stderr," Freq: %d Hz\n", ai->frequency); ai->framesize = ac3_frames[fr][frame >> 1]; if ((frame & 1) && (fr == 1)) ai->framesize++; ai->framesize = ai->framesize << 1; if (pr) fprintf (stderr," Framesize %d\n", ai->framesize); return c; } void ps_pes(ipack *p) { int check; uint8_t pbuf[PS_HEADER_L2]; static int muxr = 0; static int ai = 0; static int vi = 0; static int start = 0; static uint32_t SCR = 0; if (p->mpeg == 2){ switch(p->buf[3]){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: if (!p->has_vi){ if(get_vinfo(p->buf, p->count, &p->vi,1) >=0) { p->has_vi = 1; vi = p->vi.bit_rate; } } break; case AUDIO_STREAM_S ... AUDIO_STREAM_E: if (!p->has_ai){ if(get_ainfo(p->buf, p->count, &p->ai,1) >=0) { p->has_ai = 1; ai = p->ai.bit_rate; } } break; } if (p->has_vi && vi && !muxr){ muxr = (vi+ai)/400; } if ( start && muxr && (p->buf[7] & PTS_ONLY) && (p->has_ai || p->buf[9+p->buf[8]+4] == 0xb3)){ SCR = trans_pts_dts(p->pts)-3600; check = write_ps_header(pbuf, SCR, muxr, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); p->func(pbuf, check , p->data); } if (muxr && !start && vi){ SCR = trans_pts_dts(p->pts)-3600; check = write_ps_header(pbuf, SCR, muxr, 1, 0, 0, 1, 1, 1, 0xC0, 0, 64, 0xE0, 1, 460); start = 1; p->func(pbuf, check , p->data); } if (start) p->func(p->buf, p->count, p->data); } } void send_ipack(ipack *p) { int streamid=0; int off; int ac3_off = 0; AudioInfo ai; int nframes= 0; int f=0; if (p->count < 10) return; p->buf[3] = p->cid; p->buf[4] = (uint8_t)(((p->count-6) & 0xFF00) >> 8); p->buf[5] = (uint8_t)((p->count-6) & 0x00FF); if (p->cid == PRIVATE_STREAM1){ off = 9+p->buf[8]; streamid = p->buf[off]; if ((streamid & 0xF8) == 0x80){ ai.off = 0; ac3_off = ((p->buf[off+2] << 8)| p->buf[off+3]); if (ac3_off < p->count) f=get_ac3info(p->buf+off+3+ac3_off, p->count-ac3_off, &ai,0); if ( !f ){ nframes = (p->count-off-3-ac3_off)/ ai.framesize + 1; p->buf[off+2] = (ac3_off >> 8)& 0xFF; p->buf[off+3] = (ac3_off)& 0xFF; p->buf[off+1] = nframes; ac3_off += nframes * ai.framesize - p->count; } } } if (p->ps) ps_pes(p); else p->func(p->buf, p->count, p->data); switch ( p->mpeg ){ case 2: p->buf[6] = 0x80; p->buf[7] = 0x00; p->buf[8] = 0x00; p->count = 9; if (p->cid == PRIVATE_STREAM1 && (streamid & 0xF8)==0x80 ){ p->count += 4; p->buf[9] = streamid; p->buf[10] = (ac3_off >> 8)& 0xFF; p->buf[11] = (ac3_off)& 0xFF; p->buf[12] = 0; } break; case 1: p->buf[6] = 0x0F; p->count = 7; break; } } static void write_ipack(ipack *p, uint8_t *data, int count) { uint8_t headr[3] = { 0x00, 0x00, 0x01} ; int diff =0; if (p->count < 6){ if (trans_pts_dts(p->pts) > trans_pts_dts(p->last_pts)) memcpy(p->last_pts, p->pts, 5); p->count = 0; memcpy(p->buf+p->count, headr, 3); p->count += 6; } if ( p->size == p->size_orig && p->plength && (diff = 6+p->plength - p->found + p->count +count) > p->size && diff < 3*p->size/2){ p->size = diff/2; // fprintf(stderr,"size: %d \n",p->size); } if (p->count + count < p->size){ memcpy(p->buf+p->count, data, count); p->count += count; } else { int rest = p->size - p->count; if (rest < 0) rest = 0; memcpy(p->buf+p->count, data, rest); p->count += rest; // fprintf(stderr,"count: %d \n",p->count); send_ipack(p); if (count - rest > 0) write_ipack(p, data+rest, count-rest); } } void instant_repack (uint8_t *buf, int count, ipack *p) { int l; unsigned short *pl; int c=0; while (c < count && (p->mpeg == 0 || (p->mpeg == 1 && p->found < 7) || (p->mpeg == 2 && p->found < 9)) && (p->found < 5 || !p->done)){ switch ( p->found ){ case 0: case 1: if (buf[c] == 0x00) p->found++; else p->found = 0; c++; break; case 2: if (buf[c] == 0x01) p->found++; else if (buf[c] == 0){ p->found = 2; } else p->found = 0; c++; break; case 3: p->cid = 0; switch (buf[c]){ case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: p->done = 1; case PRIVATE_STREAM1: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case AUDIO_STREAM_S ... AUDIO_STREAM_E: p->found++; p->cid = buf[c]; c++; break; default: p->found = 0; break; } break; case 4: if (count-c > 1){ pl = (unsigned short *) (buf+c); p->plength = ntohs(*pl); p->plen[0] = buf[c]; c++; p->plen[1] = buf[c]; c++; p->found+=2; } else { p->plen[0] = buf[c]; p->found++; return; } break; case 5: p->plen[1] = buf[c]; c++; pl = (unsigned short *) p->plen; p->plength = ntohs(*pl); p->found++; break; case 6: if (!p->done){ p->flag1 = buf[c]; c++; p->found++; if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; else { p->hlength = 0; p->which = 0; p->mpeg = 1; p->flag2 = 0; } } break; case 7: if ( !p->done && p->mpeg == 2){ p->flag2 = buf[c]; c++; p->found++; } break; case 8: if ( !p->done && p->mpeg == 2){ p->hlength = buf[c]; c++; p->found++; } break; default: break; } } if (c == count) return; if (!p->plength) p->plength = MMAX_PLENGTH-6; if ( p->done || ((p->mpeg == 2 && p->found >= 9) || (p->mpeg == 1 && p->found >= 7)) ){ switch (p->cid){ case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case PRIVATE_STREAM1: if (p->mpeg == 2 && p->found == 9){ write_ipack(p, &p->flag1, 1); write_ipack(p, &p->flag2, 1); write_ipack(p, &p->hlength, 1); } if (p->mpeg == 1 && p->found == 7){ write_ipack(p, &p->flag1, 1); } if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && p->found < 14){ while (c < count && p->found < 14){ p->pts[p->found-9] = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; } if (c == count) return; } if (p->mpeg == 1 && p->which < 2000){ if (p->found == 7) { p->check = p->flag1; p->hlength = 1; } while (!p->which && c < count && p->check == 0xFF){ p->check = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; p->hlength++; } if ( c == count) return; if ( (p->check & 0xC0) == 0x40 && !p->which){ p->check = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; p->hlength++; p->which = 1; if ( c == count) return; p->check = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return; } if (p->which == 1){ p->check = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return; } if ( (p->check & 0x30) && p->check != 0xFF){ p->flag2 = (p->check & 0xF0) << 2; p->pts[0] = p->check; p->which = 3; } if ( c == count) return; if (p->which > 2){ if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY){ while (c < count && p->which < 7){ p->pts[p->which-2] = buf[c]; write_ipack(p,buf+c,1); c++; p->found++; p->which++; p->hlength++; } if ( c == count) return; } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS){ while (c < count && p->which< 12){ if (p->which< 7) p->pts[p->which -2] = buf[c]; write_ipack(p,buf+c,1); c++; p->found++; p->which++; p->hlength++; } if ( c == count) return; } p->which = 2000; } } while (c < count && p->found < p->plength+6){ l = count -c; if (l+p->found > p->plength+6) l = p->plength+6-p->found; write_ipack(p, buf+c, l); p->found += l; c += l; } break; } if ( p->done ){ if( p->found + count - c < p->plength+6){ p->found += count-c; c = count; } else { c += p->plength+6 - p->found; p->found = p->plength+6; } } if (p->plength && p->found == p->plength+6) { send_ipack(p); reset_ipack(p); if (c < count) instant_repack(buf+c, count-c, p); } } return; } void write_out_es(uint8_t *buf, int count,void *priv) { ipack *p = (ipack *) priv; u8 payl = buf[8]+9+p->start-1; write(p->fd, buf+payl, count-payl); p->start = 1; } void write_out_pes(uint8_t *buf, int count,void *priv) { ipack *p = (ipack *) priv; write(p->fd, buf, count); } int64_t ts_demux(int fdin, int fdv_out,int fda_out,uint16_t pida, uint16_t pidv, int es) { uint8_t buf[IN_SIZE]; uint8_t mbuf[TS_SIZE]; int i; int count = 1; uint16_t pid; ipack pa, pv; ipack *p; u8 *sb; int64_t apts=0; int64_t vpts=0; int verb = 0; uint64_t length =0; uint64_t l=0; int perc =0; int last_perc =0; if (fdin != STDIN_FILENO) verb = 1; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } if (!pida || !pidv) find_avpids(fdin, &pidv, &pida); if (es){ init_ipack(&pa, IPACKS,write_out_es, 0); init_ipack(&pv, IPACKS,write_out_es, 0); } else { init_ipack(&pa, IPACKS,write_out_pes, 0); init_ipack(&pv, IPACKS,write_out_pes, 0); } pa.fd = fda_out; pv.fd = fdv_out; pa.data = (void *)&pa; pv.data = (void *)&pv; count = read(fdin,mbuf,TS_SIZE); if (count) l+=count; for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); return 0; } else { memcpy(buf,mbuf+i,TS_SIZE-i); count = read(fdin,mbuf,i); if (count) l+=count; memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } count = 1; while (count > 0){ count = read(fdin,buf+i,IN_SIZE-i); if (count) l+=count; if (verb && perc >last_perc){ perc = (100*l)/length; fprintf(stderr,"Reading TS %d %%\r",perc); last_perc = perc; } for( i = 0; i < count; i+= TS_SIZE){ uint8_t off = 0; if ( count - i < TS_SIZE) break; pid = get_pid(buf+i+1); if (!(buf[3+i]&0x10)) // no payload? continue; if (pid == pidv){ p = &pv; } else { if (pid == pida){ p = &pa; } else continue; } if ( buf[3+i] & 0x20) { // adaptation field? off = buf[4+i] + 1; } if ( buf[1+i]&0x40) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; send_ipack(p); reset_ipack(p); } sb = buf+4+off+i; if( es && !p->start && (sb[7] & PTS_DTS_FLAGS)){ uint8_t *pay = sb+sb[8]+9; int l = TS_SIZE - 13 - off - sb[8]; if ( pid == pidv && (p->start = get_vinfo( pay, l,&p->vi,1)+1) >0 ){ vpts = trans_pts_dts(sb+9); printf("vpts : %fs\n", vpts/90000.); } if ( pid == pida && (p->start = get_ainfo( pay, l,&p->ai,1)+1) >0 ){ apts = trans_pts_dts(sb+9); printf("apts : %fs\n", apts/90000.); } } } if (p->start) instant_repack(buf+4+off+i, TS_SIZE-4-off, p); } i = 0; } return (vpts-apts); } void ts2es(int fdin, uint16_t pidv) { uint8_t buf[IN_SIZE]; uint8_t mbuf[TS_SIZE]; int i; int count = 1; ipack p; int verb = 0; uint64_t length =0; uint64_t l=0; int perc =0; int last_perc =0; uint16_t pid; if (fdin != STDIN_FILENO) verb = 1; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } init_ipack(&p, IPACKS,write_out_es, 0); p.fd = STDOUT_FILENO; p.data = (void *)&p; count = read(fdin,mbuf,TS_SIZE); if (count) l+=count; for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); return; } else { memcpy(buf,mbuf+i,TS_SIZE-i); count = read(fdin,mbuf,i); if (count) l+=count; memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } count = 1; while (count > 0){ count = read(fdin,buf+i,IN_SIZE-i); if (count) l+=count; if (verb && perc >last_perc){ perc = (100*l)/length; fprintf(stderr,"Reading TS %d %%\r",perc); last_perc = perc; } for( i = 0; i < count; i+= TS_SIZE){ uint8_t off = 0; if ( count - i < TS_SIZE) break; pid = get_pid(buf+i+1); if (!(buf[3+i]&0x10)) // no payload? continue; if (pid != pidv){ continue; } if ( buf[3+i] & 0x20) { // adaptation field? off = buf[4+i] + 1; } if ( buf[1+i]&0x40) { if (p.plength == MMAX_PLENGTH-6){ p.plength = p.found-6; p.found = 0; send_ipack(&p); reset_ipack(&p); } } instant_repack(buf+4+off+i, TS_SIZE-4-off, &p); } i = 0; } } void change_aspect(int fdin, int fdout, int aspect) { ps_packet ps; pes_packet pes; int neof,i; do { init_ps(&ps); neof = read_ps(fdin,&ps); write_ps(fdout,&ps); for (i = 0; i < ps.npes; i++){ u8 *buf; int c = 0; int l; init_pes(&pes); read_pes(fdin, &pes); buf = pes.pes_pckt_data; switch (pes.stream_id){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: l=pes.length; break; default: l = 0; break; } while ( c < l - 6){ if (buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01 && buf[c+3] == 0xB3) { c += 4; buf[c+3] &= 0x0f; buf[c+3] |= aspect; } else c++; } write_pes(fdout,&pes); } } while( neof > 0 ); } dvbstream-20090621.orig/dvbstream.c0000644000175000017500000013644511127355013015521 0ustar markmark/* dvbstream - RTP-ize a DVB transport stream. (C) Dave Chapman 2001, 2002. The latest version can be found at http://www.linuxstb.org/dvbstream Copyright notice: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ // Linux includes: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // DVB includes: #include #include #include "rtp.h" #include "mpegtools/transform.h" #include "mpegtools/remux.h" #include "tune.h" // The default telnet port. #define DEFAULT_PORT 12345 #define USAGE "\nUSAGE: dvbstream tpid1 tpid2 tpid3 .. tpid8\n\n" #define PACKET_SIZE 188 // How often (in seconds) to update the "now" variable #define ALARM_TIME 5 /* Thanks to Giancarlo Baracchino for this fix */ #define MTU 1500 #define IP_HEADER_SIZE 20 #define UDP_HEADER_SIZE 8 #define RTP_HEADER_SIZE 12 #define MAX_RTP_SIZE (MTU-IP_HEADER_SIZE-UDP_HEADER_SIZE-RTP_HEADER_SIZE) #define writes(f,x) write((f),(x),strlen(x)) /* Signal handling code shamelessly copied from VDR by Klaus Schmidinger - see http://www.cadsoft.de/people/kls/vdr/index.htm */ unsigned int SLOF=(11700*1000UL); unsigned int LOF1=(9750*1000UL); unsigned int LOF2=(10600*1000UL); char* frontenddev[4]={"/dev/dvb/adapter0/frontend0","/dev/dvb/adapter1/frontend0","/dev/dvb/adapter2/frontend0","/dev/dvb/adapter3/frontend0"}; char* dvrdev[4]={"/dev/dvb/adapter0/dvr0","/dev/dvb/adapter1/dvr0","/dev/dvb/adapter2/dvr0","/dev/dvb/adapter3/dvr0"}; char* demuxdev[4]={"/dev/dvb/adapter0/demux0","/dev/dvb/adapter1/demux0","/dev/dvb/adapter2/demux0","/dev/dvb/adapter3/demux0"}; int card=0; long now; long real_start_time; int Interrupted=0; fe_spectral_inversion_t specInv=INVERSION_AUTO; int tone=-1; fe_modulation_t modulation=CONSTELLATION_DEFAULT; fe_transmit_mode_t TransmissionMode=TRANSMISSION_MODE_DEFAULT; fe_bandwidth_t bandWidth=BANDWIDTH_DEFAULT; fe_guard_interval_t guardInterval=GUARD_INTERVAL_DEFAULT; fe_code_rate_t HP_CodeRate=HP_CODERATE_DEFAULT, LP_CodeRate=LP_CODERATE_DEFAULT; fe_hierarchy_t hier=HIERARCHY_DEFAULT; unsigned char diseqc=0; char pol=0; int streamtype = RTP; static int use_stdin=0; #define PID_MODE 0 #define PROG_MODE 1 static int selection_mode = PID_MODE; int open_fe(int* fd_frontend) { if((*fd_frontend = open(frontenddev[card],O_RDWR | O_NONBLOCK)) < 0){ perror("FRONTEND DEVICE: "); return -1; } return 1; } static void SignalHandler(int signum) { struct timeval tv; if (signum == SIGALRM) { gettimeofday(&tv,(struct timezone*) NULL); now=tv.tv_sec-real_start_time; alarm(ALARM_TIME); } else if (signum != SIGPIPE) { Interrupted=signum; } signal(signum,SignalHandler); } long getmsec() { struct timeval tv; gettimeofday(&tv,(struct timezone*) NULL); return(tv.tv_sec%1000000)*1000 + tv.tv_usec/1000; } // There seems to be a limit of 16 simultaneous filters in the driver #define MAX_CHANNELS 16 void set_ts_filt(int fd,uint16_t pid, dmx_pes_type_t pestype) { struct dmx_pes_filter_params pesFilterParams; //fprintf(stderr,"Setting filter for PID %d\n",pid); pesFilterParams.pid = pid; pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = DMX_OUT_TS_TAP; pesFilterParams.pes_type = pestype; pesFilterParams.flags = DMX_IMMEDIATE_START; if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { fprintf(stderr,"Failed setting filter for pid %i: ",pid); perror("DMX SET PES FILTER"); } } void make_nonblock(int f) { int oldflags; if ((oldflags=fcntl(f,F_GETFL,0)) < 0) { perror("F_GETFL"); } oldflags|=O_NONBLOCK; if (fcntl(f,F_SETFL,oldflags) < 0) { perror("F_SETFL"); } } typedef enum {STREAM_ON,STREAM_OFF} state_t; int socketIn, ns; int pids[MAX_CHANNELS]; int pestypes[MAX_CHANNELS]; unsigned char hi_mappids[8192]; unsigned char lo_mappids[8192]; int fd_frontend; int pid,pid2; int connectionOpen; int fromlen; char hostname[64]; char in_ch; struct hostent *hp; struct sockaddr_in name, fsin; int ReUseAddr=1; int oldflags; int npids = 0; int fd[MAX_CHANNELS]; int to_stdout = 0; /* to stdout instead of rtp stream */ /* rtp */ struct rtpheader hdr; struct sockaddr_in sOut; int socketOut; ipack pa, pv; #define IPACKS 2048 #define TS_SIZE 188 #define IN_SIZE TS_SIZE int process_telnet() { char cmd[1024]; int cmd_i=0; int i; char* ch; dmx_pes_type_t pestype; unsigned long freq=0; unsigned long srate=0; /* Open a new telnet session if a client is trying to connect */ if (ns==-1) { if ((ns = accept(socketIn, (struct sockaddr *)&fsin, &fromlen)) > 0) { make_nonblock(ns); cmd_i=0; cmd[0]=0; printf("Opened connection\n"); writes(ns,"220-DVBSTREAM - "); writes(ns,hostname); writes(ns,"\r\nDONE\r\n"); connectionOpen=1; } } /* If a telnet session is open, receive and process any input */ if (connectionOpen) { /* Read in at most a line of text - any ctrl character ends the line */ while (read(ns,&in_ch,1)>0) { if (in_ch < 32) break; /* Prevent buffer overflows */ if (cmd_i < 1024-1) { cmd[cmd_i++]=in_ch; cmd[cmd_i]=0; } } if (in_ch > 0) { if (cmd_i > 0) { printf("CMD: \"%s\"\n",cmd); if (strcasecmp(cmd,"QUIT")==0) { writes(ns,"DONE\r\n"); close(ns); ns=-1; connectionOpen=0; printf("Closed connection\n"); } else if (strcasecmp(cmd,"STOP")==0) { writes(ns,"STOP\n"); for (i=0;i> 8); lo_mappids[i]=(i&0xff); } writes(ns,"DONE\r\n"); } else if (strncasecmp(cmd,"ADD",3)==0) { i=4; if ((cmd[3]=='V') || (cmd[3]=='v')) pestype=DMX_PES_VIDEO; else if ((cmd[3]=='A') || (cmd[3]=='a')) pestype=DMX_PES_AUDIO; else if ((cmd[3]=='T') || (cmd[3]=='t')) pestype=DMX_PES_TELETEXT; else { pestype=DMX_PES_OTHER; i=3; } while (cmd[i]==' ') i++; if ((ch=(char*)strstr(&cmd[i],":"))!=NULL) { pid2=atoi(&ch[1]); ch[0]=0; } else { pid2=-1; } pid=atoi(&cmd[i]); if (pid) { if (npids == MAX_CHANNELS) { fprintf(stderr,"\nsorry, you can only set up to 8 filters.\n\n"); return(-1); } else { pestypes[npids]=pestype; pestype=DMX_PES_OTHER; pids[npids]=pid; if (pid2!=-1) { hi_mappids[pid]=pid2>>8; lo_mappids[pid]=pid2&0xff; fprintf(stderr,"Mapping %d to %d\n",pid,pid2); } if((fd[npids] = open(demuxdev[card],O_RDWR|O_NONBLOCK)) < 0){ fprintf(stderr,"FD %i: ",i); perror("DEMUX DEVICE: "); } else { set_ts_filt(fd[npids],pids[npids],pestypes[npids]); npids++; } } } writes(ns,"DONE\r\n"); } else if (strcasecmp(cmd,"START")==0) { writes(ns,"START\n"); for (i=0;i> 8); lo_mappids[i]=(i&0xff); } for (i=0;iplength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; send_ipack(p); reset_ipack(p); } } if ( buf[3] & 0x20) { // adaptation field? off = buf[4] + 1; } instant_repack(buf+4+off, TS_SIZE-4-off, p); } typedef uint8_t PID_BIT_MAP[1024]; static PID_BIT_MAP SI_PIDS; static PID_BIT_MAP USER_PIDS; typedef struct { char *filename; int fd; int pids[MAX_CHANNELS]; int num; int pid_cnt; int progs[MAX_CHANNELS]; int progs_cnt; uint8_t **prognames; int prognames_cnt; PID_BIT_MAP pidmap; long start_time; // in seconds long end_time; // in seconds int socket; struct rtpheader hdr; struct sockaddr_in sOut; unsigned char buf[MTU]; unsigned char net[20]; int pos; int port; } pids_map_t; pids_map_t *pids_map; int map_cnt; //1024 section payload +1 pointer +256 pointer value #define SECTION_LEN 1281 typedef struct { uint8_t buf[SECTION_LEN]; unsigned int pos; } section_t; typedef struct { int program; int pmt_pid; } pat_entry; static struct { int len; //section length int version; section_t section; pat_entry *entries; int entries_cnt; } PAT; #define MAX_PIDS 202 typedef struct { section_t section; int version; int pids[MAX_PIDS]; int pids_cnt; uint8_t name[256]; } pmt_t; struct { pmt_t *entries; int cnt; } PMT; static struct { int len; //section length int version; section_t section; } SDT; static int SI_fd[MAX_CHANNELS]; static int SI_fd_cnt = 0; #define SDT_PID 0x11 #define getbit(buf, pid) (buf[(pid)/8] & (1 << ((pid) % 8))) #define setbit(buf, pid) buf[(pid)/8] |= (1 << ((pid) % 8)) #define clearbits(buf) memset(buf, 0, sizeof(PID_BIT_MAP)) #define setallbits(buf) memset(buf, 0xFF, sizeof(PID_BIT_MAP)) #define min(x, y) ((x) <= (y) ? (x) : (y)) void update_bitmaps() { int i, j, k, n; for(i = 0; i < map_cnt; i++) { clearbits(pids_map[i].pidmap); setbit(pids_map[i].pidmap, 0); for(j = 0; j < MAX_CHANNELS; j++) { if(pids_map[i].pids[j] == -1) break; if(pids_map[i].pids[j] == 8192) { setallbits(pids_map[i].pidmap); break; } setbit(pids_map[i].pidmap, pids_map[i].pids[j]); for(k = 0; k < PMT.cnt; k++) { for(n = 0; n < PMT.entries[k].pids_cnt; n++) { if(PMT.entries[k].pids[n] == pids_map[i].pids[j]) { //add the pmt_pid to the map //fprintf(stderr, "ADDING TO map %d PMT n. %d with PID: %d, j: %d\n", i, k, PAT.entries[k].pmt_pid, j); setbit(pids_map[i].pidmap, PAT.entries[k].pmt_pid); } } } } } for(j = 0; j < map_cnt; j++) { for(k = 0; k < pids_map[j].progs_cnt; k++) { for(i = 0; i < PAT.entries_cnt; i++) { if(pids_map[j].progs[k] == PAT.entries[i].program) { setbit(pids_map[j].pidmap, PAT.entries[i].pmt_pid); setbit(pids_map[j].pidmap, SDT_PID); for(n = 0; n < PMT.entries[i].pids_cnt; n++) { int pid = PMT.entries[i].pids[n]; setbit(pids_map[j].pidmap, pid); //fprintf(stderr, "\nADDED to map %d PROG pid %d, prog: %d", j, pid, PAT.entries[i].program); } } } } } for(i = 0; i < map_cnt; i++) { for(j = 0; j < pids_map[i].prognames_cnt; j++) { for(k = 0; k < PMT.cnt; k++) { if(!strcmp(pids_map[i].prognames[j], PMT.entries[k].name)) { setbit(pids_map[i].pidmap, PAT.entries[k].pmt_pid); setbit(pids_map[i].pidmap, SDT_PID); for(n = 0; n < PMT.entries[k].pids_cnt; n++) { int pid = PMT.entries[k].pids[n]; setbit(pids_map[i].pidmap, pid); //fprintf(stderr, "\nADDED to map %d PROG pid %d, prog: %d", j, pid, PAT.entries[k].program); } } } } } } static int collect_section(section_t *section, int pusi, uint8_t *buf, unsigned int len) { int skip, slen; uint8_t *ptr; if(pusi) section->pos = 0; if(section->pos + len > SECTION_LEN) return 0; memcpy(&(section->buf[section->pos]), buf, len); section->pos += len; skip = section->buf[0]; if(skip + 4 > section->pos) return 0; ptr = &(section->buf[skip + 1]); slen = ((ptr[1] & 0x0f) << 8) | ptr[2]; if(section->pos < (skip+1+3+slen)) return 0; return skip+1; } static int parse_pat(int pusi, uint8_t *b, int l) { unsigned int i, j, vers, seclen, num, skip; uint8_t *buf; skip = collect_section(&PAT.section, pusi, b, l); if(!skip) return 0; //now we know the section is complete PAT.section.pos = 0; buf = &(PAT.section.buf[skip]); if(buf[0] != 0) //pat id return 0; if(!(buf[5] & 1)) //not yet valid return 0; vers = (buf[5] >> 1) & 0x1F; if(PAT.version == vers) //PAT didn't change return 1; clearbits(SI_PIDS); setbit(SI_PIDS, 0); setbit(SI_PIDS, SDT_PID); seclen = ((buf[1] & 0x0F) << 8) | buf[2]; num = (seclen - 9) / 4; if(PAT.entries_cnt != num) { PAT.entries = realloc(PAT.entries, sizeof(pat_entry)*num); PAT.entries_cnt = num; PMT.entries = realloc(PMT.entries, sizeof(pmt_t)*num); if(!PMT.entries) return 0; PMT.cnt = num; } i = 8; j = 0; for(j=0; jsection), pusi, b, l); if(!skip) return 0; //now we know the section is complete pmt->section.pos = 0; pmt->pids_cnt = 0; buf = &(pmt->section.buf[skip]); if(buf[0] != 2) //pmt id return 0; if(!(buf[5] & 1)) //not yet valid return 0; prog = (buf[3] << 8) | buf[4]; version = (buf[5] >> 1) & 0x1F; if(pmt->version == version) //PMT didn't change return 1; seclen = ((buf[1] & 0x0F) << 8) | buf[2]; pcr_pid = ((buf[8] & 0x1F) << 8) | buf[9]; pmt->pids[pmt->pids_cnt++] = pcr_pid; //fprintf(stderr, "\nPROGRAM: %d, pcr_pid: %d, version: %d vs %d\n", prog, pcr_pid, pmt->version, version); skip = ((buf[10] & 0x0F) << 8) | buf[11]; if(skip+12 > seclen) return 0; i = skip+12; while(i+5pids[pmt->pids_cnt++] = pid; skip = ((buf[i+3] & 0x0F) << 8) | buf[i+4]; i += skip+5; //fprintf(stderr, "prog %d, PID: %d, count: %d, type: 0x%x\n", prog, pid, pmt->pids_cnt, buf[i]); } pmt->version = version; return 2; } static int parse_sdt(int pusi, uint8_t *b, int l) { unsigned int i, version, seclen, skip, prog, k, descr_len, found, len; uint8_t *buf; skip = collect_section(&(SDT.section), pusi, b, l); if(!skip) return 0; buf = &(SDT.section.buf[skip]); if(buf[0] != 0x42) //pmt id return 0; if(!(buf[5] & 1)) //not yet valid return 0; version = (buf[5] >> 1) & 0x1F; if(SDT.version == version) //SDT didn't change return 1; seclen = ((buf[1] & 0x0F) << 8) | buf[2]; if(seclen < 12) return 0; i = 11; while(i < seclen - 4) { descr_len = ((buf[i+3] & 0x0F) << 8) | buf[i+4]; if(i+5+descr_len >= seclen) break; prog = (buf[i] << 8) | buf[i+1]; found = -1; k = 0; for(k = 0; k < PAT.entries_cnt, k < PMT.cnt; k++) if(PAT.entries[k].program == prog) { found = k; if(k != -1) { int j, len, dlen; j = i + 5; len = dlen = 0; while(len < descr_len) { int provider_len, name_len, n; pmt_t *pmt; n = j; dlen = buf[n+1]; if(len + dlen > descr_len) break; if(buf[n] == 0x48) { provider_len = buf[n+3]; if(provider_len + 2 > dlen) break; n += 4 + provider_len; name_len = buf[n]; if(provider_len + 3 + name_len > dlen) break; pmt = &PMT.entries[k]; memcpy(pmt->name, &buf[n+1], name_len); pmt->name[name_len] = 0; fprintf(stderr, "Program n. %d, name: '%s'\n", prog, pmt->name); } len += dlen+2; j += dlen+2; } } } i += 5 + descr_len; } SDT.version = version; return 2; } static int parse_ts_packet(uint8_t *buf) { int pid, l, af, pusi; if(buf[0] != 0x47) return 0; pusi = buf[1] & 0x40; pid = ((buf[1] & 0x1F) << 8) | buf[2]; af = (buf[3] >> 4) & 0x03; l = 4; if(af == 2) //only adaption return 0; else if(af == 3) l += buf[4] + 1; if(l >= TS_SIZE - 4) return 0; if(pid == 0) { if(parse_pat(pusi, &buf[l], TS_SIZE - l) == 2) add_pmt_pids(); } else if(pid == SDT_PID) { if(parse_sdt(pusi, &buf[l], TS_SIZE - l) == 2) { int i; for(i = 0; i < PMT.cnt; i++) { PMT.entries[i].section.pos = SECTION_LEN+1; PMT.entries[i].version = -1; } update_bitmaps(); } } else { int i; for(i=0; i> 8); lo_mappids[i]=(i&0xff); counts[i]=0; } memset(&PAT, 0, sizeof(PAT)); PAT.version = -1; PAT.section.pos = SECTION_LEN+1; memset(&PMT, 0, sizeof(PMT)); clearbits(SI_PIDS); setbit(SI_PIDS, 0); memset(&SDT, 0, sizeof(SDT)); SDT.section.pos = SECTION_LEN+1; SDT.version = -1; setbit(SI_PIDS, SDT_PID); clearbits(USER_PIDS); setbit(USER_PIDS, 0); /* Set default IP and port */ strcpy(ipOut,"224.0.1.2"); portOut = 5004; if (argc==1) { fprintf(stderr,"Usage: dvbtune [OPTIONS] pid1 pid2 ... pid8\n\n"); fprintf(stderr,"-i IP multicast address\n"); fprintf(stderr,"-r IP multicast port\n"); fprintf(stderr,"-net ip:prt IP address:port combination to be followed by pids list. Can be repeated to generate multiple RTP streams\n"); fprintf(stderr,"-o Stream to stdout instead of network\n"); fprintf(stderr,"-o:file.ts Stream to named file instead of network\n"); fprintf(stderr,"-n secs Stop after secs seconds\n"); fprintf(stderr,"-from n Start saving the file previously specified with -o: syntax in n minutes time\n"); fprintf(stderr,"-to n Stop saving the file previously specified with -o: syntax in n minutes time\n"); fprintf(stderr,"-ps Convert stream to Program Stream format (needs exactly 2 pids)\n"); fprintf(stderr,"-v vpid Decode video PID (full cards only)\n"); fprintf(stderr,"-a apid Decode audio PID (full cards only)\n"); fprintf(stderr,"-t ttpid Decode teletext PID (full cards only)\n"); fprintf(stderr,"\nStandard tuning options:\n\n"); fprintf(stderr,"-f freq absolute Frequency (DVB-S in Hz or DVB-T in Hz)\n"); fprintf(stderr," or L-band Frequency (DVB-S in Hz or DVB-T in Hz)\n"); fprintf(stderr,"-SL slof S-LOF(DVB-S only)\n"); fprintf(stderr,"-L1 LOF1 LOF1(DVB-S only)\n"); fprintf(stderr,"-L2 LOF2 LOF2(DVB-S only)\n"); fprintf(stderr,"-p [H,V] Polarity (DVB-S only)\n"); fprintf(stderr,"-s N Symbol rate (DVB-S or DVB-C)\n"); fprintf(stderr,"\nAdvanced tuning options:\n\n"); fprintf(stderr,"-c [0-3] Use DVB card #[0-3]\n"); fprintf(stderr,"-D [0-4AB] DiSEqC command (0=none)\n\n"); fprintf(stderr,"-I [0|1|2] 0=Spectrum Inversion off, 1=Spectrum Inversion on, 2=auto\n"); fprintf(stderr,"-qam X DVB-T/C and ATSC modulation - 16%s, 32%s, 64%s, 128%s or 256%s\n",(CONSTELLATION_DEFAULT==QAM_16 ? " (default)" : ""),(CONSTELLATION_DEFAULT==QAM_32 ? " (default)" : ""),(CONSTELLATION_DEFAULT==QAM_64 ? " (default)" : ""),(CONSTELLATION_DEFAULT==QAM_128 ? " (default)" : ""),(CONSTELLATION_DEFAULT==QAM_256 ? " (default)" : "")); #ifdef DVB_ATSC fprintf(stderr,"-vsb X ATSC modulation - 8, 16\n"); #endif fprintf(stderr,"-gi N DVB-T guard interval 1_N (N=32%s, 16%s, 8%s or 4%s)\n",(GUARD_INTERVAL_DEFAULT==GUARD_INTERVAL_1_32 ? " (default)" : ""),(GUARD_INTERVAL_DEFAULT==GUARD_INTERVAL_1_16 ? " (default)" : ""),(GUARD_INTERVAL_DEFAULT==GUARD_INTERVAL_1_8 ? " (default)" : ""),(GUARD_INTERVAL_DEFAULT==GUARD_INTERVAL_1_4 ? " (default)" : "")); fprintf(stderr,"-cr N DVB-T/C code rate. N=AUTO%s, 1_2%s, 2_3%s, 3_4%s, 5_6%s, 7_8%s\n",(HP_CODERATE_DEFAULT==FEC_AUTO ? " (default)" : ""),(HP_CODERATE_DEFAULT==FEC_1_2 ? " (default)" : ""),(HP_CODERATE_DEFAULT==FEC_2_3 ? " (default)" : ""),(HP_CODERATE_DEFAULT==FEC_3_4 ? " (default)" : ""),(HP_CODERATE_DEFAULT==FEC_5_6 ? " (default)" : ""),(HP_CODERATE_DEFAULT==FEC_7_8 ? " (default)" : "")); fprintf(stderr,"-crlp N DVB-T code rate LP. N=AUTO%s, 1_2%s, 2_3%s, 3_4%s, 5_6%s, 7_8%s\n",(LP_CODERATE_DEFAULT==FEC_AUTO ? " (default)" : ""),(LP_CODERATE_DEFAULT==FEC_1_2 ? " (default)" : ""),(LP_CODERATE_DEFAULT==FEC_2_3 ? " (default)" : ""),(LP_CODERATE_DEFAULT==FEC_3_4 ? " (default)" : ""),(LP_CODERATE_DEFAULT==FEC_5_6 ? " (default)" : ""),(LP_CODERATE_DEFAULT==FEC_7_8 ? " (default)" : "")); fprintf(stderr,"-bw N DVB-T bandwidth (Mhz) - N=6%s, 7%s or 8%s\n",(BANDWIDTH_DEFAULT==BANDWIDTH_6_MHZ ? " (default)" : ""),(BANDWIDTH_DEFAULT==BANDWIDTH_7_MHZ ? " (default)" : ""),(BANDWIDTH_DEFAULT==BANDWIDTH_8_MHZ ? " (default)" : "")); fprintf(stderr,"-tm N DVB-T transmission mode - N=2%s or 8%s\n",(TRANSMISSION_MODE_DEFAULT==TRANSMISSION_MODE_2K ? " (default)" : ""),(TRANSMISSION_MODE_DEFAULT==TRANSMISSION_MODE_8K ? " (default)" : "")); fprintf(stderr,"-hy N DVB-T hierarchy - N=1%s, 2%s, 4%s, NONE%s or AUTO%s\n",(HIERARCHY_DEFAULT==HIERARCHY_1 ? " (default)" : ""),(HIERARCHY_DEFAULT==HIERARCHY_2 ? " (default)" : ""),(HIERARCHY_DEFAULT==HIERARCHY_4 ? " (default)" : ""),(HIERARCHY_DEFAULT==HIERARCHY_NONE ? " (default)" : ""),(HIERARCHY_DEFAULT==HIERARCHY_AUTO ? " (default)" : "")); fprintf(stderr,"-ttl N Sets TTL to N (default: 2) when streaming in RTP\n"); fprintf(stderr,"-rtp Sets output type to RTP (default when using network out)\n"); fprintf(stderr,"-udp Sets output type to UDP \n"); fprintf(stderr,"-prog Selects PROGRAM mode (opens a demux on the whole TS)\n"); fprintf(stderr,"-pid Selects PID mode (default)\n"); fprintf(stderr,"-stdin Use STDIN as source rather than a DVB card\n"); fprintf(stderr,"\n-analyse Perform a simple analysis of the bitrates of the PIDs in the transport stream\n"); fprintf(stderr,"\n"); fprintf(stderr,"NOTE: Use pid1=8192 to broadcast whole TS stream from a budget card\n"); return(-1); } else { pids[0]=0; npids=1; pestype=DMX_PES_OTHER; // Default PES type for (i=1;i 19)) { fprintf(stderr, "No valid IP:port found after -net switch, discarding\n"); } else { int len = (int) (tmp - argv[i]); char addr[20]; int port; strncpy(ipOut, argv[i], len); ipOut[len] = 0; strncpy(addr, argv[i], len); addr[len] = 0; port = portOut = atoi(tmp+1); pids_map = (pids_map_t*) realloc(pids_map, sizeof(pids_map_t) * (map_cnt+1)); if(pids_map != NULL) { map_cnt++; pids_map[map_cnt-1].pid_cnt = 0; pids_map[map_cnt-1].progs_cnt = 0; pids_map[map_cnt-1].start_time=start_time; pids_map[map_cnt-1].end_time=end_time; for(j=0; j < MAX_CHANNELS; j++) pids_map[map_cnt-1].pids[j] = -1; pids_map[map_cnt-1].filename = NULL; strncpy(pids_map[map_cnt-1].net, addr, len); pids_map[map_cnt-1].net[len] = 0; pids_map[map_cnt-1].port = port; pids_map[map_cnt-1].pos = 0; pids_map[map_cnt-1].socket = makesocket(addr,port,ttl,&(pids_map[map_cnt-1].sOut)); initrtp(&(pids_map[map_cnt-1].hdr),(output_type==RTP_TS ? 33 : 34), streamtype); output_type = MAP_TS; } else fprintf(stderr, "Couldn't alloc enough entry for this %s:%d address\n", addr, port); } } else if (strcmp(argv[i],"-f")==0) { i++; freq=atoi(argv[i]); } else if (strcmp(argv[i],"-p")==0) { i++; if (argv[i][1]==0) { if (tolower(argv[i][0])=='v') { pol='V'; } else if (tolower(argv[i][0])=='h') { pol='H'; } } } else if (strcmp(argv[i],"-SL")==0) { i++; SLOF=atoi(argv[i]); SLOF*=1000UL; } else if (strcmp(argv[i],"-L1")==0) { i++; LOF1=atoi(argv[i]); LOF1*=1000UL; } else if (strcmp(argv[i],"-L2")==0) { i++; LOF2=atoi(argv[i]); LOF2*=1000UL; } else if (strcmp(argv[i],"-s")==0) { i++; srate=atoi(argv[i])*1000UL; } else if (strcmp(argv[i],"-D")==0) { i++; diseqc = argv[i][0]; if(toupper(diseqc) == 'A') diseqc = 'A'; else if(toupper(diseqc) == 'B') diseqc = 'B'; else if(diseqc >= '0' && diseqc <= '4') { diseqc=diseqc - '0'; } else { fprintf(stderr,"DiSEqC must be between 0 and 4 or A | B\n"); exit(-1); } } else if (strcmp(argv[i],"-I")==0) { i++; if (atoi(argv[i])==0) specInv = INVERSION_OFF; else if (atoi(argv[i])==1) specInv = INVERSION_ON; else specInv = INVERSION_AUTO; } else if(strcmp(argv[i],"-prog")==0) { selection_mode = PROG_MODE; } else if(strcmp(argv[i],"-pid")==0) { selection_mode = PID_MODE; } else if (strcmp(argv[i],"-o")==0) { to_stdout = 1; } else if (strcmp(argv[i],"-n")==0) { i++; secs=atoi(argv[i]); } else if (strcmp(argv[i],"-c")==0) { i++; card=atoi(argv[i]); if ((card < 0) || (card > 3)) { fprintf(stderr,"ERROR: card parameter must be between 0 and 4\n"); } } else if (strcmp(argv[i],"-v")==0) { pestype=DMX_PES_VIDEO; } else if (strcmp(argv[i],"-a")==0) { pestype=DMX_PES_AUDIO; } else if (strcmp(argv[i],"-t")==0) { pestype=DMX_PES_TELETEXT; } else if (strcmp(argv[i],"-qam")==0) { i++; switch(atoi(argv[i])) { case 16: modulation=QAM_16; break; case 32: modulation=QAM_32; break; case 64: modulation=QAM_64; break; case 128: modulation=QAM_128; break; case 256: modulation=QAM_256; break; default: fprintf(stderr,"Invalid QAM rate: %s\n",argv[i]); exit(0); } } #ifdef DVB_ATSC else if(strcmp(argv[i],"-vsb")==0) { i++; switch(atoi(argv[i])) { case 8: modulation=VSB_8; break; case 16: modulation=VSB_16; break; default: fprintf(stderr,"Invalid ATSC VSB modulation: %s\n",argv[i]); exit(0); } } #endif else if (strcmp(argv[i],"-gi")==0) { i++; switch(atoi(argv[i])) { case 32: guardInterval=GUARD_INTERVAL_1_32; break; case 16: guardInterval=GUARD_INTERVAL_1_16; break; case 8: guardInterval=GUARD_INTERVAL_1_8; break; case 4: guardInterval=GUARD_INTERVAL_1_4; break; default: fprintf(stderr,"Invalid Guard Interval: %s\n",argv[i]); exit(0); } } else if (strcmp(argv[i],"-tm")==0) { i++; switch(atoi(argv[i])) { case 8: TransmissionMode=TRANSMISSION_MODE_8K; break; case 2: TransmissionMode=TRANSMISSION_MODE_2K; break; default: fprintf(stderr,"Invalid Transmission Mode: %s\n",argv[i]); exit(0); } } else if (strcmp(argv[i],"-bw")==0) { i++; switch(atoi(argv[i])) { case 8: bandWidth=BANDWIDTH_8_MHZ; break; case 7: bandWidth=BANDWIDTH_7_MHZ; break; case 6: bandWidth=BANDWIDTH_6_MHZ; break; default: fprintf(stderr,"Invalid DVB-T bandwidth: %s\n",argv[i]); exit(0); } } else if (strcmp(argv[i],"-cr")==0) { i++; if (!strcmp(argv[i],"AUTO")) { HP_CodeRate=FEC_AUTO; } else if (!strcmp(argv[i],"1_2")) { HP_CodeRate=FEC_1_2; } else if (!strcmp(argv[i],"2_3")) { HP_CodeRate=FEC_2_3; } else if (!strcmp(argv[i],"3_4")) { HP_CodeRate=FEC_3_4; } else if (!strcmp(argv[i],"5_6")) { HP_CodeRate=FEC_5_6; } else if (!strcmp(argv[i],"7_8")) { HP_CodeRate=FEC_7_8; } else { fprintf(stderr,"Invalid Code Rate: %s\n",argv[i]); exit(0); } } else if (strcmp(argv[i],"-crlp")==0) { i++; if (!strcmp(argv[i],"AUTO")) { LP_CodeRate=FEC_AUTO; } else if (!strcmp(argv[i],"1_2")) { LP_CodeRate=FEC_1_2; } else if (!strcmp(argv[i],"2_3")) { LP_CodeRate=FEC_2_3; } else if (!strcmp(argv[i],"3_4")) { LP_CodeRate=FEC_3_4; } else if (!strcmp(argv[i],"5_6")) { LP_CodeRate=FEC_5_6; } else if (!strcmp(argv[i],"7_8")) { LP_CodeRate=FEC_7_8; } else { fprintf(stderr,"Invalid Code Rate LP: %s\n",argv[i]); exit(0); } } else if (strcmp(argv[i],"-hier")==0) { i++; if (!strcmp(argv[i],"AUTO")) { hier=HIERARCHY_AUTO; } else if (!strcmp(argv[i],"1")) { hier=HIERARCHY_2; } else if (!strcmp(argv[i],"4")) { hier=HIERARCHY_4; } else if (!strcmp(argv[i],"NONE")) { hier=HIERARCHY_NONE; } else { fprintf(stderr,"Invalid HIERARCHY: %s\n",argv[i]); exit(0); } } else if (strcmp(argv[i],"-ttl")==0) { i++; ttl = atoi(argv[i]); } else if (strcmp(argv[i],"-from")==0) { i++; if (map_cnt) { pids_map[map_cnt-1].start_time=atoi(argv[i])*60; } else { start_time=atoi(argv[i])*60; } } else if (strcmp(argv[i],"-to")==0) { i++; if (map_cnt) { pids_map[map_cnt-1].end_time=atoi(argv[i])*60; } else { end_time=atoi(argv[i])*60; secs=end_time; } } else if (strstr(argv[i], "-o:")==argv[i]) { if (strlen(argv[i]) > 3) { char * fname; fname = (char *) malloc(strlen(argv[i]) - 2); if(fname == NULL) { fprintf(stderr, "Couldn't alloc enough memory for this -o: entry, discarding\n"); } else { strcpy(fname, &argv[i][3]); pids_map = (pids_map_t*) realloc(pids_map, sizeof(pids_map_t) * (map_cnt+1)); if(pids_map != NULL) { map_cnt++; pids_map[map_cnt-1].pid_cnt = 0; pids_map[map_cnt-1].start_time=start_time; pids_map[map_cnt-1].end_time=end_time; for(j=0; j < MAX_CHANNELS; j++) pids_map[map_cnt-1].pids[j] = -1; pids_map[map_cnt-1].filename = fname; output_type = MAP_TS; } else fprintf(stderr, "Couldn't alloc enough memory for file %s: entry, discarding\n", fname); } } } else { if ((ch=(char*)strstr(argv[i],":"))!=NULL) { pid2=atoi(&ch[1]); ch[0]=0; } else { pid2=-1; } pid=atoi(argv[i]); // If we are currently processing a "-o:" option: if (map_cnt) { if(selection_mode == PID_MODE) { // block for the map found = 0; for (j=0;jprognames_cnt;j++) { if(!strcmp(map->prognames[j], argv[i])) found = 1; } if(found == 0) { map->prognames = realloc(map->prognames, (map->prognames_cnt+1)*sizeof(map->prognames)); map->prognames_cnt++; map->prognames[map->prognames_cnt-1] = malloc(strlen(argv[i])+1); strcpy(map->prognames[map->prognames_cnt-1], argv[i]); } } else { for (j=0;j>8; lo_mappids[pid]=pid2&0xff; fprintf(stderr,"Mapping %d to %d\n",pid,pid2); } } } } } } } if ((output_type==RTP_PS) && (npids!=3)) { fprintf(stderr,"ERROR: PS requires exactly two PIDS - video and audio.\n"); exit(1); } for (i=0;i 0) fprintf(stderr, "\n"); for (i=0;i 0) { if (bytes_read!=PACKET_SIZE) { fprintf(stderr,"No bytes left to read - aborting\n"); break; } pid=((free_bytes[1]&0x1f) << 8) | (free_bytes[2]); free_bytes[1]=(free_bytes[1]&0xe0)|hi_mappids[pid]; free_bytes[2]=lo_mappids[pid]; free_bytes+=bytes_read; // If there isn't enough room for 1 more packet, then send it. if ((free_bytes+PACKET_SIZE-buf)>MAX_RTP_SIZE) { hdr.timestamp = getmsec()*90; if (to_stdout) { write(1, buf, free_bytes-buf); } else { sendrtp2(socketOut,&sOut,&hdr,buf,free_bytes-buf); } free_bytes = buf; } count++; } } else if (output_type==RTP_PS) { if (read(fd_dvr,buf,TS_SIZE) > 0) { my_ts_to_ps((uint8_t*)buf, pids[1], pids[2]); } else if(use_stdin) break; } else if(output_type==MAP_TS) { int bytes_read; bytes_read = read(fd_dvr, buf, TS_SIZE); if(bytes_read > 0) { if(buf[0] == 0x47) { int pid, i; pid = ((buf[1] & 0x1f) << 8) | buf[2]; if(getbit(SI_PIDS, pid)) parse_ts_packet(buf); if (pids_map != NULL) { for (i = 0; i < map_cnt; i++) { if ( ((pids_map[i].start_time==-1) || (pids_map[i].start_time <= now)) && ((pids_map[i].end_time==-1) || (pids_map[i].end_time >= now))) { if(getbit(pids_map[i].pidmap, pid)) { errno = 0; if(pids_map[i].filename) write(pids_map[i].fd, buf, TS_SIZE); else { if((pids_map[i].pos + PACKET_SIZE) > MAX_RTP_SIZE) { hdr.timestamp = getmsec()*90; sendrtp2(pids_map[i].socket, &(pids_map[i].sOut), &(pids_map[i].hdr), pids_map[i].buf, pids_map[i].pos); pids_map[i].pos = 0; } memcpy(&(pids_map[i].buf[pids_map[i].pos]), buf, bytes_read); pids_map[i].pos += bytes_read; } } } } } } else { fprintf(stderr, "NON 0X47\n"); } } else if(use_stdin) break; } else { if (do_analyse) { if (read(fd_dvr,buf,TS_SIZE) > 0) { pid=((buf[1]&0x1f) << 8) | (buf[2]); counts[pid]++; } } } if ((secs!=-1) && (secs <=now)) { Interrupted=1; } } if (Interrupted) { fprintf(stderr,"Caught signal %d - closing cleanly.\n",Interrupted); } if (ns!=-1) close(ns); close(socketIn); if (!to_stdout && !map_cnt) close(socketOut); if(!use_stdin) { for (i=0;i= 1.0) { fprintf(stdout,"%d,%.3f Mbit/s\n",i,f); } else { fprintf(stdout,"%d,%.0f kbit/s\n",i,f*1024); } } } } return(0); } dvbstream-20090621.orig/server.c0000644000175000017500000000526507470507536015052 0ustar markmark/* * Connects to port 1234 on the local host. */ #include #include #include #include #include #define NSTRS 3 /* no. of strings */ /* * Strings we send to the client. */ char *strs[NSTRS] = { "This is the first string from the server.\n", "This is the second string from the server.\n", "This is the third string from the server.\n" }; extern int errno; main() { unsigned short int port=1234; char c; FILE *fp; int fromlen; char hostname[64]; struct hostent *hp; struct sockaddr_in sin, fsin; register int i, s, ns; /* * Before we can do anything, we need * to know our hostname. */ gethostname(hostname, sizeof(hostname)); /* * Now we look up our host to get * its network number. */ if ((hp = gethostbyname(hostname)) == NULL) { fprintf(stderr, "%s: host unknown.\n", hostname); exit(1); } /* * Get a socket to work with. This socket will * be in the Internet domain, and will be a * stream socket. */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("server: socket"); exit(1); } /* * Create the address that we will be binding to. * We use port 1234 but put it into network * byte order. Also, we use bcopy (see * Chapter 14) to copy the network number. */ sin.sin_family = AF_INET; sin.sin_port = htons(port); bcopy(hp->h_addr, &sin.sin_addr, hp->h_length); /* * Try to bind the address to the socket. */ if (bind(s, &sin, sizeof(sin)) < 0) { perror("server: bind"); exit(1); } /* * Listen on the socket. */ while (1) { if (listen(s, 5) < 0) { perror("server: listen"); exit(1); } /* * Accept connections. When we accept one, ns * will be connected to the client. fsin will * contain the address of the client. */ if ((ns = accept(s, &fsin, &fromlen)) < 0) { perror("server: accept"); exit(1); } /* * We'll use stdio for reading the socket. */ fp = fdopen(ns, "r"); /* * First we send some strings to the client. */ // for (i = 0; i < NSTRS; i++) // send(ns, strs[i], strlen(strs[i]), 0); /* * Then we read some strings from the client * and print them out. */ while ((c = fgetc(fp)) != EOF) { if (c == '^') break; putchar(c); fflush(NULL); } /* * We can simply use close() to terminate the * connection, since we're done with both sides. */ } close(s); exit(0); } dvbstream-20090621.orig/Makefile0000644000175000017500000000173510026542204015014 0ustar markmark CC=gcc CFLAGS = -g -Wall -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE OBJS=dvbstream dumprtp ts_filter rtpfeed rtp.o INCS=-I ../DVB/include ifdef UK CFLAGS += -DUK endif ifdef FINLAND CFLAGS += -DFINLAND endif ifdef FINLAND2 CFLAGS += -DFINLAND2 endif all: $(OBJS) dvbstream: dvbstream.c rtp.o tune.o mpegtools/ctools.o mpegtools/remux.o mpegtools/transform.o mpegtools/ringbuffy.o $(CC) $(INCS) $(CFLAGS) -o dvbstream dvbstream.c rtp.o tune.o mpegtools/ctools.o mpegtools/remux.o mpegtools/transform.o mpegtools/ringbuffy.o dumprtp: dumprtp.c rtp.o $(CC) $(INCS) $(CFLAGS) -o dumprtp dumprtp.c rtp.o rtpfeed: rtpfeed.c rtp.o $(CC) $(INCS) $(CFLAGS) -o rtpfeed rtpfeed.c rtp.o rtp.o: rtp.c rtp.h $(CC) $(INCS) $(CFLAGS) -c -o rtp.o rtp.c tune.o: tune.c tune.h dvb_defaults.h $(CC) $(INCS) $(CFLAGS) -c -o tune.o tune.c ts_filter: ts_filter.c $(CC) $(INCS) $(CFLAGS) -o ts_filter ts_filter.c clean: rm -f *.o mpegtools/*.o *~ $(OBJS) dvbstream-20090621.orig/dvb_defaults.h0000644000175000017500000000564510470125413016175 0ustar markmark/* dvb_defaults.h Provided by Tomi Ollila Copyright (C) Dave Chapman 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #ifndef _DVB_DEFAULTS_H #define _DVB_DEFAULTS_H /* DVB-S */ // With a diseqc system you may need different values per LNB. I hope // no-one ever asks for that :-) extern unsigned int SLOF; extern unsigned int LOF1; extern unsigned int LOF2; /* DVB-T */ /* Either uncomment one of the following lines, or add it to your "make" command. e.g. make FINLAND=1 */ //#define UK //#define FINLAND //#define FINLAND2 /* UK defines are at the end, as a default option */ #ifdef FINLAND /* FINLAND settings 1 */ #define DVB_T_LOCATION "Suomessa" #define BANDWIDTH_DEFAULT BANDWIDTH_8_MHZ #define HP_CODERATE_DEFAULT FEC_2_3 #define CONSTELLATION_DEFAULT QAM_64 #define TRANSMISSION_MODE_DEFAULT TRANSMISSION_MODE_8K #define GUARD_INTERVAL_DEFAULT GUARD_INTERVAL_1_8 #define HIERARCHY_DEFAULT HIERARCHY_NONE #endif #ifdef FINLAND2 /* FINLAND settings 2 (someone verify there is such environment) */ #define DVB_T_LOCATION "Suomessa II" #define BANDWIDTH_DEFAULT BANDWIDTH_8_MHZ #define HP_CODERATE_DEFAULT FEC_1_2 #define CONSTELLATION_DEFAULT QAM_64 #define TRANSMISSION_MODE_DEFAULT TRANSMISSION_MODE_2K #define GUARD_INTERVAL_DEFAULT GUARD_INTERVAL_1_8 #define HIERARCHY_DEFAULT HIERARCHY_NONE #endif #if defined (UK) && defined (HP_CODERATE_DEFAULT) #error Multible countries defined #endif #ifndef DVB_T_LOCATION #ifndef UK #warning No DVB-T country defined in dvb_defaults.h #warning defaulting to UK #warning Ignore this if using Satellite or Cable #endif /* UNITED KINGDOM settings */ #define DVB_T_LOCATION "in United Kingdom" #define BANDWIDTH_DEFAULT BANDWIDTH_8_MHZ #define HP_CODERATE_DEFAULT FEC_2_3 #define CONSTELLATION_DEFAULT QAM_64 #define TRANSMISSION_MODE_DEFAULT TRANSMISSION_MODE_2K #define GUARD_INTERVAL_DEFAULT GUARD_INTERVAL_1_32 #define HIERARCHY_DEFAULT HIERARCHY_NONE #endif #if HIERARCHY_DEFAULT == HIERARCHY_NONE && !defined (LP_CODERATE_DEFAULT) #define LP_CODERATE_DEFAULT (FEC_NONE) /* unused if HIERARCHY_NONE */ #endif #endif dvbstream-20090621.orig/tune.h0000644000175000017500000000115010167211027014471 0ustar markmark#ifndef _TUNE_H #define _TUNE_H #include #include #include "dvb_defaults.h" #undef DVB_ATSC #if defined(DVB_API_VERSION_MINOR) #if DVB_API_VERSION == 3 && DVB_API_VERSION_MINOR >= 1 #define DVB_ATSC 1 #endif #endif int tune_it(int fd_frontend, unsigned int freq, unsigned int srate, char pol, int tone, fe_spectral_inversion_t specInv, unsigned char diseqc,fe_modulation_t modulation,fe_code_rate_t HP_CodeRate,fe_transmit_mode_t TransmissionMode,fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth, fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier); #endif dvbstream-20090621.orig/tune.c0000644000175000017500000002160110676301126014474 0ustar markmark/* dvbtune - tune.c Copyright (C) Dave Chapman 2001,2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include #include #include #include #include #include "tune.h" void print_status(FILE* fd,fe_status_t festatus) { fprintf(fd,"FE_STATUS:"); if (festatus & FE_HAS_SIGNAL) fprintf(fd," FE_HAS_SIGNAL"); if (festatus & FE_TIMEDOUT) fprintf(fd," FE_TIMEDOUT"); if (festatus & FE_HAS_LOCK) fprintf(fd," FE_HAS_LOCK"); if (festatus & FE_HAS_CARRIER) fprintf(fd," FE_HAS_CARRIER"); if (festatus & FE_HAS_VITERBI) fprintf(fd," FE_HAS_VITERBI"); if (festatus & FE_HAS_SYNC) fprintf(fd," FE_HAS_SYNC"); fprintf(fd,"\n"); } struct diseqc_cmd { struct dvb_diseqc_master_cmd cmd; uint32_t wait; }; static int diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd, fe_sec_tone_mode_t t, unsigned char sat_no) { if(ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) < 0) return -1; if(ioctl(fd, FE_SET_VOLTAGE, v) < 0) return -1; usleep(15 * 1000); if(sat_no >= 1 && sat_no <= 4) //1.x compatible equipment { if(ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) < 0) return -1; usleep(cmd->wait * 1000); usleep(15 * 1000); } else //A or B simple diseqc { fprintf(stderr, "SETTING SIMPLE %c BURST\n", sat_no); if(ioctl(fd, FE_DISEQC_SEND_BURST, (sat_no == 'B' ? SEC_MINI_B : SEC_MINI_A)) < 0) return -1; usleep(15 * 1000); } if(ioctl(fd, FE_SET_TONE, t) < 0) return -1; return 0; } /* digital satellite equipment control, * specification is available from http://www.eutelsat.com/ */ static int do_diseqc(int fd, unsigned char sat_no, int polv, int hi_lo) { struct diseqc_cmd cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 }; if(sat_no != 0) { unsigned char d = sat_no; /* param: high nibble: reset bits, low nibble set bits, * bits are: option, position, polarizaion, band */ cmd.cmd.msg[3] = 0xf0 | (((sat_no * 4) & 0x0f) | (polv ? 0 : 2) | (hi_lo ? 1 : 0)); return diseqc_send_msg(fd, polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18, &cmd, hi_lo ? SEC_TONE_ON : SEC_TONE_OFF, d); } else //only tone and voltage { fprintf(stderr, "Setting only tone %s and voltage %dV\n", (hi_lo ? "ON" : "OFF"), (polv ? 13 : 18)); if(ioctl(fd, FE_SET_VOLTAGE, (polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18)) < 0) return -1; if(ioctl(fd, FE_SET_TONE, (hi_lo ? SEC_TONE_ON : SEC_TONE_OFF)) < 0) return -1; usleep(15 * 1000); return 0; } } int check_status(int fd_frontend,int type, struct dvb_frontend_parameters* feparams,unsigned int base) { int32_t strength; fe_status_t festatus; struct pollfd pfd[1]; int locks=0, ok=0; time_t tm1, tm2; if (ioctl(fd_frontend,FE_SET_FRONTEND,feparams) < 0) { perror("ERROR tuning channel\n"); return -1; } pfd[0].fd = fd_frontend; pfd[0].events = POLLPRI; tm1 = tm2 = time((time_t*) NULL); fprintf(stderr,"Getting frontend status\n"); while (!ok) { festatus = 0; if (poll(pfd,1,3000) > 0){ if (pfd[0].revents & POLLPRI){ if(ioctl(fd_frontend,FE_READ_STATUS,&festatus) >= 0) if(festatus & FE_HAS_LOCK) locks++; } } usleep(10000); tm2 = time((time_t*) NULL); if((festatus & FE_TIMEDOUT) || (locks >= 2) || (tm2 - tm1 >= 3)) ok = 1; } if (festatus & FE_HAS_LOCK) { if(ioctl(fd_frontend,FE_GET_FRONTEND,feparams) >= 0) { switch(type) { case FE_OFDM: fprintf(stderr,"Event: Frequency: %d\n",feparams->frequency); break; case FE_QPSK: fprintf(stderr,"Event: Frequency: %d\n",(unsigned int)(feparams->frequency + base)); fprintf(stderr," SymbolRate: %d\n",feparams->u.qpsk.symbol_rate); fprintf(stderr," FEC_inner: %d\n",feparams->u.qpsk.fec_inner); fprintf(stderr,"\n"); break; case FE_QAM: fprintf(stderr,"Event: Frequency: %d\n",feparams->frequency); fprintf(stderr," SymbolRate: %d\n",feparams->u.qpsk.symbol_rate); fprintf(stderr," FEC_inner: %d\n",feparams->u.qpsk.fec_inner); break; #ifdef DVB_ATSC case FE_ATSC: fprintf(stderr, "Event: Frequency: %d\n",feparams->frequency); fprintf(stderr, " Modulation: %d\n",feparams->u.vsb.modulation); break; #endif default: break; } } strength=0; if(ioctl(fd_frontend,FE_READ_BER,&strength) >= 0) fprintf(stderr,"Bit error rate: %d\n",strength); strength=0; if(ioctl(fd_frontend,FE_READ_SIGNAL_STRENGTH,&strength) >= 0) fprintf(stderr,"Signal strength: %d\n",strength); strength=0; if(ioctl(fd_frontend,FE_READ_SNR,&strength) >= 0) fprintf(stderr,"SNR: %d\n",strength); strength=0; if(ioctl(fd_frontend,FE_READ_UNCORRECTED_BLOCKS,&strength) >= 0) fprintf(stderr,"UNC: %d\n",strength); print_status(stderr,festatus); } else { fprintf(stderr,"Not able to lock to the signal on the given frequency\n"); return -1; } return 0; } int tune_it(int fd_frontend, unsigned int freq, unsigned int srate, char pol, int tone, fe_spectral_inversion_t specInv, unsigned char diseqc,fe_modulation_t modulation,fe_code_rate_t HP_CodeRate,fe_transmit_mode_t TransmissionMode,fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth, fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier) { int res, hi_lo, dfd; unsigned int base; struct dvb_frontend_parameters feparams; struct dvb_frontend_info fe_info; if ( (res = ioctl(fd_frontend,FE_GET_INFO, &fe_info) < 0)){ perror("FE_GET_INFO: "); return -1; } fprintf(stderr,"Using DVB card \"%s\", freq=%d\n",fe_info.name, freq); if (freq < 1000000) freq*=1000UL; switch(fe_info.type) { case FE_OFDM: feparams.frequency=freq; feparams.inversion=INVERSION_OFF; feparams.u.ofdm.bandwidth=bandwidth; feparams.u.ofdm.code_rate_HP=HP_CodeRate; feparams.u.ofdm.code_rate_LP=LP_CodeRate; feparams.u.ofdm.constellation=modulation; feparams.u.ofdm.transmission_mode=TransmissionMode; feparams.u.ofdm.guard_interval=guardInterval; feparams.u.ofdm.hierarchy_information=hier; fprintf(stderr,"tuning DVB-T (%s) to %d Hz, Bandwidth: %d\n",DVB_T_LOCATION,freq, bandwidth==BANDWIDTH_8_MHZ ? 8 : (bandwidth==BANDWIDTH_7_MHZ ? 7 : 6)); break; case FE_QPSK: pol = toupper(pol); if (freq > 2200000) { if (freq < SLOF) { feparams.frequency=(freq-LOF1); hi_lo = 0; base = LOF1; } else { feparams.frequency=(freq-LOF2); hi_lo = 1; base = LOF2; } } else { feparams.frequency=freq; base = 0; } fprintf(stderr,"tuning DVB-S to Freq: %u, Pol:%c Srate=%d, 22kHz tone=%s, LNB: %d, SLOF %d, LOF1: %d, LOF2: %d\n", feparams.frequency,pol,srate,tone == SEC_TONE_ON ? "on" : "off", diseqc, SLOF/1000UL, LOF1/1000UL, LOF2/1000UL); feparams.inversion=specInv; feparams.u.qpsk.symbol_rate=srate; feparams.u.qpsk.fec_inner=FEC_AUTO; dfd = fd_frontend; if(do_diseqc(dfd, diseqc, (pol == 'V' ? 1 : 0), hi_lo) == 0) fprintf(stderr, "DISEQC SETTING SUCCEDED\n"); else { fprintf(stderr, "DISEQC SETTING FAILED\n"); return -1; } break; case FE_QAM: fprintf(stderr,"tuning DVB-C to %d, srate=%d\n",freq,srate); feparams.frequency=freq; feparams.inversion=INVERSION_OFF; feparams.u.qam.symbol_rate = srate; feparams.u.qam.fec_inner = FEC_AUTO; feparams.u.qam.modulation = modulation; break; #ifdef DVB_ATSC case FE_ATSC: fprintf(stderr, "tuning ATSC to %d, modulation=%d\n",freq,modulation); feparams.frequency=freq; feparams.u.vsb.modulation = modulation; break; #endif default: fprintf(stderr,"Unknown FE type. Aborting\n"); exit(-1); } usleep(100000); return(check_status(fd_frontend,fe_info.type,&feparams,base)); } dvbstream-20090621.orig/rtptv.sh0000644000175000017500000000027407741324521015076 0ustar markmark#!/bin/sh DUMPRTP=/home/dave/DVB/cvs/dvbstream/dumprtp TS2PS=/home/dave/src/mpegtools/ts2ps BFR=bfr MPLAYER='mplayer -ao sdl -vo sdl -' $DUMPRTP | $TS2PS 0 0 | $BFR -m 1024kB | $MPLAYER dvbstream-20090621.orig/CHANGES0000644000175000017500000000150207470507536014361 0ustar markmarkV0.4 - 29th October 2001: ------------------------- Improved error checking in dumprtp client Added initial implementation of telnet interface - see README for details. V0.3 - 15th October 2001: ------------------------- Updated tuning code to use latest tuning API changes in driver. Added "PID mapping" feature Added -v -a -t switches to route streams to the hardware decoders on the DVB card as well as streaming. Added signal handling (copied from VDR). V0.2 - 6th September 2001: -------------------------- Added tuning facility to dvbstream. Fixed bug with handling of fatal errors in dvbstream (thanks to Guenter Wildmann). Added rtpfeed client (by Guenter Wildmann) that uses a DVB card on the client machine to play back a broadcasted stream. V0.1 - 5th September 2001: -------------------------- Initial release. dvbstream-20090621.orig/TELNET/0000755000175000017500000000000011424666467014366 5ustar markmarkdvbstream-20090621.orig/TELNET/itn.sh0000755000175000017500000000021707470507544015513 0ustar markmark./svdrpsend.pl -d kenny -p 12345 tune 12031 h 27500 ./svdrpsend.pl -d kenny -p 12345 addv 2308:1 ./svdrpsend.pl -d kenny -p 12345 adda 2310:2 dvbstream-20090621.orig/TELNET/cnn.sh0000755000175000017500000000021707470507544015477 0ustar markmark./svdrpsend.pl -d kenny -p 12345 tune 12051 v 27500 ./svdrpsend.pl -d kenny -p 12345 addv 2319:1 ./svdrpsend.pl -d kenny -p 12345 adda 2321:2 dvbstream-20090621.orig/TELNET/svdrpsend.pl0000755000175000017500000000222207470507544016730 0ustar markmark#!/usr/bin/perl use Socket; use Getopt::Std; $Usage = qq{ Usage: $0 options command... Options: -d hostname destination hostname (default: localhost) -p port SVDRP port number (default: 2001) }; die $Usage if (!$ARGV[0] || !getopts("d:p:")); $Dest = $opt_d || "localhost"; $Port = $opt_p || 2001; $Cmd = "@ARGV" || Error("missing command"); $Timeout = 10; # max. seconds to wait for response $SIG{ALRM} = sub { Error("timeout"); }; alarm($Timeout); $iaddr = inet_aton($Dest) || Error("no host: $Dest"); $paddr = sockaddr_in($Port, $iaddr); $proto = getprotobyname('tcp'); socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!"); connect(SOCK, $paddr) || Error("connect: $!"); select(SOCK); $| = 1; Receive(); Send($Cmd); Send("quit"); close(SOCK) || Error("close: $!"); sub Send { my $cmd = shift || Error("no command to send"); print SOCK "$cmd\r\n"; Receive(); } sub Receive { while () { print STDOUT $_; last if substr($_, 3, 1) ne "-"; } } sub Error { print STDERR "@_\n"; close(SOCK); exit 0; } dvbstream-20090621.orig/TELNET/virgin.sh0000755000175000017500000000012207470507544016212 0ustar markmark./svdrpsend.pl -d kenny -p 12345 stop ./svdrpsend.pl -d kenny -p 12345 adda 640:2 dvbstream-20090621.orig/TELNET/xfm.sh0000755000175000017500000000012207470507544015506 0ustar markmark./svdrpsend.pl -d kenny -p 12345 stop ./svdrpsend.pl -d kenny -p 12345 adda 643:2 dvbstream-20090621.orig/TELNET/README0000644000175000017500000000030407470507544015237 0ustar markmarkThese scripts provide example usage of the telnet interface to dvbstream. They tune to different TV and Radio stations on Astra 28E. svdrpsend.pl is copied from Klaus Schmidinger's VDR package. dvbstream-20090621.orig/rtp.h0000644000175000017500000000250210210111501014306 0ustar markmark#ifndef _RTP_H #define _RTP_H #include enum {RTP_PS,RTP_TS,RTP_NONE,MAP_TS}; enum {RTP, UDP}; struct rtpbits { unsigned int v:2; /* version: 2 */ unsigned int p:1; /* is there padding appended: 0 */ unsigned int x:1; /* number of extension headers: 0 */ unsigned int cc:4; /* number of CSRC identifiers: 0 */ unsigned int m:1; /* marker: 0 */ unsigned int pt:7; /* payload type: 33 for MPEG2 TS - RFC 1890 */ unsigned int sequence:16; /* sequence number: random */ }; struct rtpheader { /* in network byte order */ struct rtpbits b; int timestamp; /* start: random */ int ssrc; /* random */ int type; /* RTP or UDP */ }; void initrtp(struct rtpheader *foo,int pt, int type); /* fill in the MPEG-2 TS deefaults */ int sendrtp(int fd, struct sockaddr_in *sSockAddr, struct rtpheader *foo, char *data, int len); int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData); int sendrtp2(int fd, struct sockaddr_in *sSockAddr, struct rtpheader *foo, char *data, int len); int getrtp(int fd, struct rtpheader *rh, char** data, int* lengthData); int makesocket(char *szAddr,unsigned short port,int TTL,struct sockaddr_in *sSockAddr); int makeclientsocket(char *szAddr,unsigned short port,int TTL,struct sockaddr_in *sSockAddr); #endif dvbstream-20090621.orig/rtpfeed.c0000644000175000017500000000771710026542205015160 0ustar markmark/* * rtpfeed.c: get an rtp unicast/multicast/broacast stream and feed * the DVB-S card with it * Author: Guenter Wildmann * * Parts taken from dumprtp.c by David Podeur * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at g.wildmann@it-lab.at, */ // Linux includes: #include #include #include #include #include #include #include #include #include #include #include "rtp.h" // DVB includes: #include #include void dumprtp(int socket, int fd_dvr) { char* buf; struct rtpheader rh; int lengthData; int written; while(1) { getrtp2(socket,&rh, &buf,&lengthData); written = 0; while(written < lengthData){ written += write(fd_dvr,buf+written, lengthData-written); }//end while }//end while }// end dumprtp void set_ts_filt(int fd,uint16_t pid, int type) { struct dmx_pes_filter_params pesFilterParams; pesFilterParams.pid = pid; pesFilterParams.input = DMX_IN_DVR; pesFilterParams.output = DMX_OUT_DECODER; if (type==1) pesFilterParams.pes_type = DMX_PES_VIDEO; if (type==2) pesFilterParams.pes_type = DMX_PES_AUDIO; pesFilterParams.flags = DMX_IMMEDIATE_START; if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { fprintf(stderr,"FILTER %i: ",pid); perror("DMX SET PES FILTER"); }// end if }// end set_ts_filt int main(int argc, char *argv[]) { // filedescriptors for video, audio and dvr-device int fda,fdv; int fd_dvr; // pids for video and audio stream uint16_t vpid = 0; uint16_t apid = 0; struct sockaddr_in si; int socketIn; char *ip = "224.0.1.2"; int port = 5004; // process command-line arguments static struct option long_options[]={ {"group", required_argument, NULL, 'g'}, {"port", required_argument, NULL, 'p'}, {"vpid", required_argument, NULL, 'v'}, {"apid", required_argument, NULL, 'a'}, {"help", no_argument, NULL, 'h'}, {0} }; int c; int option_index = 0; fprintf(stderr,"*** rtpfeed 0.1 ***\n"); while((c = getopt_long(argc, argv, "g:p:v:a:h",long_options, &option_index))!=-1) { switch(c) { case 'g': ip = optarg; break; case 'p': port = atoi(optarg); break; case 'v': vpid = atoi(optarg); break; case 'a': apid = atoi(optarg); break; case 'h': fprintf(stderr,"Usage: %s [-g group] [-p port] [-v video PID] [-a audio PID] \n",argv[0]); exit(1); }// end switch }// end while // open dvr device for output if((fd_dvr = open("/dev/ost/dvr",O_WRONLY)) < 0){ perror("DVR DEVICE: "); return -1; } // open video device, set filters if(vpid!=0){ if((fdv = open("/dev/ost/demux",O_RDWR|O_NONBLOCK)) < 0){ perror("DEMUX DEVICE: "); return -1; }// end if set_ts_filt(fdv, vpid, 1); }// end if // open audio device, set filters if(apid!=0){ if((fda = open("/dev/ost/demux",O_RDWR|O_NONBLOCK)) < 0){ perror("DEMUX DEVICE: "); return -1; }// end if set_ts_filt(fda, apid, 2); }// end if socketIn = makeclientsocket(ip,port,2,&si); dumprtp(socketIn, fd_dvr); close(socketIn); return(0); } dvbstream-20090621.orig/README0000644000175000017500000001245210013426541014233 0ustar markmarkDVBstream - v0.6 ---------------- INTRODUCTION DVBstream is based on the ts-rtp package available at http://www.linuxtv.org. It broadcasts a (subset of a) DVB transport stream over a LAN using the rtp protocol. There were a couple of small bugs in the original ts-rtp application, which I have fixed here. v0.4pre2 of dvbstream introduced the "-ps" option which performs on-the-fly conversion of the stream to a PS before either streaming it or writing it to stdout. However, this option is not needed with recent versions of MPlayer and xine - they have native Transport Stream support. REQUIREMENTS This software requires Linux, a supported DVB card, the Linux DVB drivers from www.linuxtv.org and a kernel with Multicast networking enabled. See the Multicasting HOWTO for more information on multicasting. In brief, just set CONFIG_IP_MULTICAST=y (the default on my SuSE 7.1 installation) and recompile your kernel (if required). You can then set up the "route" using a command like: /sbin/route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0 INSTALLATION Just type "make" to compile (you may need to change the path to the DVB include files in the first line of the Makefile). If you are using dvbtune for DVB-T in Finland, you should replace the "make" command with "make FINLAND=1". or "make FINLAND2=1" (see the comments in the dvb_defaults.h file for details). USAGE - SERVER If you wanted to broadcast TVC International from Astra 19E, you would type the following command: dvbstream -f 12441 -p v -s 27500 512 660 You can specify up to 8 PIDs on the command-line to include in the multicasted transport stream. A 10MBit/s network should be able to handle one video and one audio stream, or eight audio streams. If you also want to view the TV channel on the TV-OUT of your DVB-S card (or using xawtv or similar), then you can use the "-v" and "-a" flags before the video and audio PIDs respectively: dvbstream -f 12441 -p v -s 27500 -v 512 -a 660 dvbstream also has the ability to map PIDS to different values before you stream it. For example, if you type dvbstream -f 12441 -p v -s 27500 -v 512:1 -a 660:2 then the video stream will become "PID 1" and the audio stream will become "PID 2". Also, with driver versions from October 2001 onwards, you can broadcast the entire transport stream (if you are using a budget card) with the command: dvbstream 8192 8192 is a "dummy PID" (legal PIDS are in the range 0-8191) and the driver interprets this to mean the entire TS. Obviously, it would make no sense to use the map feature on this "pid". USAGE - CLIENT To receive the stream on any other machine on your LAN, use the dumprtp utility (from ts-rtp). An slightly improved version is included in this archive. e.g. dumprtp > received.ts If you have a DVB card on the second machine, you can use the rtpfeed command to decode the stream. Type "rtpfeed -h" for usage information. rtpfeed was written by Guenter Wildmann - please address any bugs or comments to Guenter. If you don't have a DVB card on the client machine, You can use mpg123 and the mpegtools provided with the DVB driver for live audio decoding: dumprtp | ts2es apid | mpg123 - This command line is included with dvbstream as the "rtpradio.sh" script. If you only want audio, you can run dvbstream with eight audio PIDs, and then your clients can choose which PID to play. For live TV channel playing, the best solution I have found is mplayer (http://www.mplayerhq.hu). Please install the latest CVS version - mplayer is being rapidly improved. You can then view TV being streamed over the network using the following command: mplayer -cache 2048 rtp://224.0.1.2:5004/ TELNET INTERFACE From v0.4 onwards, DVBstream incorporates a "telnet" interface to allow you to remotely start and stop the streaming, and tune the card to a different channel. The following commands are supported: TUNE freq pol srate STOP ADDV pid[:map] ADDA pid[:map] ADDT pid[:map] ADD pid[:map] QUIT STOP closes down all PIDs and stops the streaming. The other commands should be self-explanatory. See the scripts in the TELNET directory for example usage. CONTRIBUTORS The ts2ps conversion is taken from the "mpegtools" package distributed with the linuxtv.org DVB driver. This code is (C) 2000, 2001 Marcus Metzler for Convergence Integrated Media Gmbh and released under the GNU GPL. rtp.c is a slightly modified version of the sendrtp_ts.c file included with the "ts-rtp" package (also from linuxtv.org). It was writen by David Podeur for Convergence Integrated Media Gmbh and released under the GNU GPL. Stephen Davies for the implementation of the "-o" and "-t" switches. COPYRIGHT NOTICE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. dvbstream-20090621.orig/rtpradio.sh0000644000175000017500000000022607470507533015545 0ustar markmark#!/bin/sh DUMPRTP=/home/dave/DVB/dvbstream-0.2/dumprtp TS2ES=/home/dave/DVB/DVB/apps/mpegtools/ts2es MPG123='mpg123 -' $DUMPRTP | $TS2ES 2 | $MPG123 dvbstream-20090621.orig/do_route.sh0000755000175000017500000000015607470507531015544 0ustar markmark#!/bin/sh # SET UP MULTICAST ROUTING (MUST BE ROOT) /sbin/route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0