summaryrefslogtreecommitdiff
path: root/libdvbmpeg/ctools.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdvbmpeg/ctools.c')
-rw-r--r--libdvbmpeg/ctools.c2379
1 files changed, 2379 insertions, 0 deletions
diff --git a/libdvbmpeg/ctools.c b/libdvbmpeg/ctools.c
new file mode 100644
index 0000000..dfd1751
--- /dev/null
+++ b/libdvbmpeg/ctools.c
@@ -0,0 +1,2379 @@
+/*
+ * dvb-mpegtools for the Siemens Fujitsu DVB PCI card
+ *
+ * Copyright (C) 2000, 2001 Marcus Metzler
+ * for convergence integrated media GmbH
+ * Copyright (C) 2002 Marcus Metzler
+ *
+ * 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 mocm@metzlerbros.de,
+ */
+
+#include "ctools.h"
+
+#define MAX_SEARCH 1024 * 1024
+
+
+/*
+
+ PES
+
+*/
+
+ssize_t save_read(int fd, void *buf, size_t count)
+{
+ ssize_t neof = 1;
+ size_t re = 0;
+
+ while(neof >= 0 && re < count){
+ neof = read(fd, buf+re, count - re);
+ if (neof > 0) re += neof;
+ else break;
+ }
+
+ if (neof < 0 && re == 0) return neof;
+ else return re;
+}
+
+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 = (uint8_t *) NULL;
+ p->pck_sqnc_cntr = 0;
+ p->org_stuff_length = 0;
+ p->pes_ext_lngth = 0;
+ p->pes_ext = (uint8_t *) NULL;
+ p->pes_pckt_data = (uint8_t *) 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 = (uint8_t *)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 = (uint8_t *) malloc(p->length);
+}
+
+void pts2pts(uint8_t *av_pts, uint8_t *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(uint8_t *buf, pes_packet *p, long length){
+ int count,i;
+ uint8_t dummy;
+ int more = 0;
+ uint8_t 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;i<p->stuffing;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;
+ uint8_t *buf;
+ int l = p->length+p->pes_hlength;
+
+ buf = (uint8_t *) 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;
+ uint8_t 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 = save_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){
+
+ uint8_t 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 += 3;
+ count -= 3;
+ }
+
+ if (p->flags2 & DSM_TRICK_FLAG){
+ memcpy(&p->trick,buf+c,1);
+ c += 1;
+ 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 = (uint8_t *)
+ 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 = (uint8_t *)
+ 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 = (uint8_t *)
+ 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 = (uint8_t *) 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){
+
+ uint8_t sync4[4];
+ int found=0;
+ uint64_t po = 0;
+ int neof = 1;
+ uint8_t *buf;
+
+ while (neof > 0 && !found) {
+ po = lseek(f,0,SEEK_CUR);
+ if (po < 0) return -1;
+ if ((neof = save_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 = save_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 = (uint8_t *) malloc(p->length);
+ if((neof = save_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(uint8_t *buf, ts_packet *p, long length){
+ long count,i;
+ uint8_t 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;
+ uint8_t buf[TS_SIZE];
+
+ length = cwrite_ts(buf,p,TS_SIZE);
+ write(fd,buf,length);
+}
+
+int read_ts (int f, ts_packet *p){
+ uint8_t sync;
+ int found=0;
+ uint64_t po,q;
+ int neof = 1;
+
+ sync=0;
+ while (neof > 0 && !found) {
+ neof = save_read(f,&sync,1);
+ if (sync == 0x47)
+ found = 1;
+ }
+ neof = save_read(f,p->pid,2);
+ neof = save_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 = save_read(f,p->data,184);
+ p->rest = 184;
+ return neof;
+ }
+
+ if ( p->flags & ADAPT_FIELD ) {
+ // adaption field
+ neof = save_read(f,&p->adapt_length,1);
+ po = lseek(f,0,SEEK_CUR);
+ neof = save_read(f,&p->adapt_flags,1);
+
+ if ( p->adapt_flags & PCR_FLAG )
+ neof = save_read(f, p->pcr,6);
+
+ if ( p->adapt_flags & OPCR_FLAG )
+ neof = save_read(f, p->opcr,6);
+
+ if ( p->adapt_flags & SPLICE_FLAG )
+ neof = save_read(f, &p->splice_count,1);
+
+ if( p->adapt_flags & TRANS_PRIV){
+ neof = save_read(f,&p->priv_dat_len,1);
+ p->priv_dat = (uint8_t *) malloc(p->priv_dat_len);
+ neof = save_read(f,p->priv_dat,p->priv_dat_len);
+ }
+
+ if( p->adapt_flags & ADAP_EXT_FLAG){
+ neof = save_read(f,&p->adapt_ext_len,1);
+ neof = save_read(f,&p->adapt_eflags,1);
+ if( p->adapt_eflags & LTW_FLAG)
+ neof = save_read(f,p->ltw,2);
+
+ if( p->adapt_eflags & PIECE_RATE)
+ neof = save_read(f,p->piece_rate,3);
+
+ if( p->adapt_eflags & SEAM_SPLICE)
+ neof = save_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 = save_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){
+ uint8_t 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 = (uint8_t *) 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 = (uint8_t *) malloc(p->sheader_length);
+}
+
+int mux_ps(ps_packet *p)
+{
+ uint32_t mux = 0;
+ uint8_t *i = (uint8_t *)&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)
+{
+ uint32_t rate=0;
+ uint8_t *i= (uint8_t *) &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;
+}
+
+
+uint32_t scr_base_ps(ps_packet *p) // only 32 bit!!
+{
+ uint32_t base = 0;
+ uint8_t *buf = (uint8_t *)&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;
+}
+
+uint16_t 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(uint8_t *buf, ps_packet *p, long length)
+{
+ long count,i;
+ uint8_t headr1[4] = {0x00, 0x00, 0x01, 0xBA };
+ uint8_t headr2[4] = {0x00, 0x00, 0x01, 0xBB };
+ uint8_t 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;
+ uint8_t buf[PS_MAX];
+
+ length = cwrite_ps(buf,p,PS_MAX);
+ write(fd,buf,length);
+}
+
+int read_ps (int f, ps_packet *p){
+ uint8_t 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 = save_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 = save_read(f,p->scr,6);
+ if (p->scr[0] & 0x40)
+ p->mpeg = 2;
+ else
+ p->mpeg = 1;
+
+ if (p->mpeg == 2){
+ neof = save_read(f,p->mux_rate,3);
+ neof = save_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 = save_read(f,p->mux_rate+1,2);
+ }
+
+ po = lseek(f,0,SEEK_CUR);
+ neof = save_read(f,headr,4);
+ if (headr[0] == 0x00 && headr[1] == 0x00 &&
+ headr[2] == 0x01 && headr[3] == 0xBB ) {
+ neof = save_read(f,p->sheader_llength,2);
+ setl_ps(p);
+ if (p->mpeg == 2){
+ neof = save_read(f,p->rate_bound,3);
+ neof = save_read(f,&p->audio_bound,1);
+ neof = save_read(f,&p->video_bound,1);
+ neof = save_read(f,&p->reserved,1);
+ }
+ neof = save_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 = save_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){
+ uint8_t *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 = (uint8_t *)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 = (uint8_t *)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 = (uint8_t *)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, uint16_t pid, uint8_t *mask, uint8_t *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(uint8_t *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;
+ tfilter(p);
+ }
+
+ if (c < count) trans_filt(buf+c,count-c,p);
+}
+
+
+void tfilter(trans *p)
+{
+ int l,c;
+ int tpid;
+ uint8_t flag,flags;
+ uint8_t adapt_length = 0;
+ uint8_t cpid[2];
+
+
+ // fprintf(stderr,"tfilter\n");
+
+ cpid[0] = p->packet[1];
+ cpid[1] = p->packet[2];
+ tpid = get_pid(cpid);
+
+ if ( p->packet[1]&0x80){
+ fprintf(stderr,"Error in TS for PID: %d\n",
+ tpid);
+ }
+
+ 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;
+ uint8_t *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,uint8_t **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;
+ uint8_t *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, uint8_t *pts,int fd)
+{
+ long muxr = 37500;
+ uint8_t audio_bound = 1;
+ uint8_t fixed = 0;
+ uint8_t CSPS = 0;
+ uint8_t audio_lock = 1;
+ uint8_t video_lock = 1;
+ uint8_t video_bound = 1;
+ uint8_t stream1 = 0XC0;
+ uint8_t buffer1_scale = 1;
+ uint32_t buffer1_size = 32;
+ uint8_t stream2 = 0xE0;
+ uint8_t buffer2_scale = 1;
+ uint32_t 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] = (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;
+
+ 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);
+
+ 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);
+
+ write_ps(fd, p);
+ kill_ps(p);
+}
+
+
+
+void twrite(uint8_t 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)(uint8_t 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(uint8_t 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( uint8_t const *buf, long int length, uint16_t 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( uint8_t const *buf, long int length, uint16_t pid, uint8_t *counter,
+ void (*ts_write)(uint8_t const *))
+{
+
+ int l, pes_start;
+ uint8_t 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;
+}
+
+extern int errno;
+const char * strerrno (void)
+{
+ return strerror(errno);
+}