poc-0.4.2/0000775000175000001440000000000010230546615012742 5ustar manuelusers00000000000000poc-0.4.2/texify.pl0000664000175000001440000000763510165025647014626 0ustar manuelusers00000000000000#! /usr/bin/perl while ($_ = shift) { scan_file($_, 0); } #for ($i=1; $ARGV[$i]; $i++) { # scan_file($ARGV[$i], 1); #} #scan_file($ARGV[0], 0); sub scan_file { local $filename = shift; local $definitions_only = shift; open(FILE, $filename); local $line = 0; local $header_symbol = 'C'; local $first_code_line = 0; print_header($filename); while ( ) { $line++; if ( /^\s*\/\*([DMISCH])/ ) { if ( $header_symbol eq 'H' ) { print $header_text; } elsif ( $header_symbol eq 'D' ) { $text =~ s/^[\s\n]*\n//; $text =~ s/[\s\n]*$/\n/; $header_text =~ s/\#([\w\_\-\.\>]+)/\\verb!$1!/go; $header_text =~ s/\"([\w\_\-\.\>]+)\"/{\\em $1}/go; $tag_header{$tag} = $header_text; #print "$tag -> $tag_header{$tag}"; $tag_body{$tag} = $text; $tag_filename{$tag} = $filename; $tag_first_code_line{$tag} = $first_code_line; $tag_code_lines{$tag} = $code_lines; $tag = ""; } elsif ( $definitions_only ) { } elsif ( $header_symbol eq 'I' ) { $text =~ s/^[\s\n]*\n//; $text =~ s/[\s\n]*$/\n/; $header_text =~ s/\#([\w\_\-\.\>]+)/\\verb!$1!/go; $header_text =~ s/\"([\w\_\-\.\>]+)\"/{\\em $1}/go; print_info($tag_filename{$tag}, $tag_first_code_line{$tag}, $tag_first_code_line{$tag} + $tag_code_lines{$tag}, $header_text ."\n". $tag_header{$tag}, $tag_body{$tag}); if ( $text =~ /\S/ ) { print_info($filename, $first_code_line, $first_code_line + $code_lines, "", $text); } } elsif ( $header_symbol eq 'M' ) { $text =~ s/^[\s\n]*\n//; $text =~ s/[\s\n]*$/\n/; $header_text =~ s/\#([\w\_\-\.\>]+)/{\\small\\em\\verb!$1!}/go; $header_text =~ s/\"([^\"]+)\"/{\\em $1}/go; print_info($filename, $first_code_line, $first_code_line + $code_lines, $header_text, $text); } elsif ( $header_symbol eq 'S' ) { $text =~ s/^[\s\n]*\n//; $text =~ s/[\s\n]*$/\n/; $header_text =~ s/^[\s\n]*//; $header_text =~ s/^(\S.*)//; print "\\subsection{$1}\n"; $header_text =~ s/^[\s\n]*//; $header_text =~ s/\#([\w\_\-\.\>]+)/\\verb!$1!/go; $header_text =~ s/\"([\w\_\-\.\>]+)\"/{\\em $1}/go; print_info($filename, $first_code_line, $first_code_line + $code_lines, $header_text, $text); } if ( $1 eq 'D' ) { $in_insert_definition = 1; $tag = ""; } else { $in_insert_definition = 0; } $header_symbol = $1; $in_header = 1; $text = ""; } elsif ( /^\s*\/\*([^\s@])/ ) { print "Unknown literal $1 in $ARGV[$i]. on $line\n"; exit(0); } elsif ( /^\s*\@(\S+)\s/ ) { $tag = $1; } elsif ( m/\*\*\/\s*$/ ) { $header_text = $text; $first_code_line = $line + 1; $in_header = 0; $text = ""; $code_lines = -1; $code_lines_pre = 0; } else { $text .= $_; if ( $text =~ /\S/ ) { $code_lines_pre++; if ( $_ =~ /\S/ ) { $code_lines += $code_lines_pre; $code_lines_pre = 0; } } else { $first_code_line++; } } } if ( $tag =~ /\S/ ) { $tag_header{$tag} = $header_text; $tag_body{$tag} = $text; $tag_filename{$tag} = $filename; $tag_first_code_line{$tag} = $first_code_line; } close(FILE); } sub print_info { local $filename = shift; local $first_code_line = shift; local $last_code_line = shift; local $header_text = shift; local $text = shift; $filename =~ s/\_/\\\_/go; print "$header_text"; if ( $text =~ m/\S/ ) { print "\\vspace{5mm}\n\\begin{lstlisting}". "[title={\\raisebox{2mm}[0pt][0pt]{". "\\hspace{9cm}\\footnotesize $filename, ". "{\\em lines $first_code_line - $last_code_line}}},". "firstnumber=$first_code_line]{}\n". "$text\\end{lstlisting}\n"; } } sub print_header { local $filename = shift; use File::Basename; my $file = basename($filename); print "\\section{$file}\n\\label{code:$file}\n\n"; } poc-0.4.2/misc.h0000664000175000001440000000042010214014115014025 0ustar manuelusers00000000000000/* * (c) 2005 bl0rg.net * * Misc functions (mostly unix workarounds) */ #ifndef MISC_H__ #define MISC_H__ #include int unix_write(int fd, unsigned char *buf, size_t size); int unix_read(int fd, unsigned char *buf, size_t size); #endif /* MISC_H__ */ poc-0.4.2/mp3cue.h0000664000175000001440000000246410165025647014321 0ustar manuelusers00000000000000/*C (c) 2003 bl0rg crew **/ #ifndef MP3CUE_H__ #define MP3CUE_H__ /*M \emph{Arbitrary maximal length for strings in a CUE file.} If you don't like it, change it. **/ #define MP3CUE_MAX_STRING_LENGTH 64 /*M \emph{CUE index structure.} This is reverse engineered and by no means correct. I also don't know what the correct name for ``centiseconds'' is. **/ typedef struct mp3cue_index_s { unsigned int minutes; unsigned int seconds; unsigned int centiseconds; } mp3cue_index_t; /*M \emph{CUE track type.} Reverse engineered. **/ typedef enum mp3cue_track_type_e { mp3cue_audio = 0 } mp3cue_track_type_t; /*M \emph{CUE track structure.} Reverse engineered. **/ typedef struct mp3cue_track_s { mp3cue_track_type_t type; int number; char title[MP3CUE_MAX_STRING_LENGTH + 1]; char performer[MP3CUE_MAX_STRING_LENGTH + 1]; mp3cue_index_t index; } mp3cue_track_t; /*M \emph{CUE file structure.} Reverse engineered. **/ typedef struct mp3cue_file_s { char performer[MP3CUE_MAX_STRING_LENGTH + 1]; char title[MP3CUE_MAX_STRING_LENGTH + 1]; unsigned int track_number; unsigned int max_track_number; mp3cue_track_t *tracks; } mp3cue_file_t; #define MP3CUE_DEFAULT_TRACK_NUMBER 20 #endif /* MP3CUE_H__ */ poc-0.4.2/poc-2250.c0000664000175000001440000002156010214014115014244 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #ifdef WITH_OPENSSL #include #include #include #endif #include #include #include #include #include #include #include #ifdef NEED_GETOPT_H__ #include #endif #include "mp3.h" #include "network.h" #include "rtp.h" #include "signal.h" #include "file.h" #ifdef WITH_IPV6 static int use_ipv6 = 0; #endif /* WITH_IPV6 */ #define MAX_FILENAME 256 #ifdef WITH_OPENSSL RSA *rsa = NULL; #endif /* WITH_OPENSSL */ #ifdef DEBUG_PLOSS int ploss_rate = 20; #endif /* DEBUG_PLOSS */ static int finished = 0; /*M \emph{Maximal synchronization latency for sending packets.} In usecs. **/ #define MAX_WAIT_TIME (1 * 1000 * 1000) rtp_pkt_t pkt; static void sig_int(int signo) { finished = 1; } /*M \emph{Simple RTP RFC2250 streaming server main loop.} The mainloop opens the MPEG Audio file \verb|filename|, reads each frame into an rtp packet and sends it out using the UDP socket \verb|sock|. After sending a packet, the mainloop sleeps for the duration of the packet, synchronizing itself when the sleep is not accurate enough. If the sleep desynchronizes itself from the stream more than \verb|MAX_WAIT_TIME|, the synchronization is reset. **/ int poc_mainloop(int sock, char *filename, int quiet) { /*M Open file for reading. **/ file_t mp3_file; if (!file_open_read(&mp3_file, filename)) { fprintf(stderr, "Could not open mp3 file: %s\n", filename); return 0; } /*M Set the M-bit of packetheader. **/ pkt.b.m = 1; static long wait_time = 0; unsigned long rtp_time = 0; /*M Get start time. **/ struct timeval tv; gettimeofday(&tv, NULL); unsigned long start_sec, start_usec; start_sec = tv.tv_sec; start_usec = tv.tv_usec; /*M Cycle through the frames and send them using RTP. **/ mp3_frame_t mp3_frame; while ((mp3_next_frame(&mp3_file, &mp3_frame) > 0) && !finished) { /*M Fill rtp packet. **/ pkt.timestamp = (rtp_time) / 11.1111; memcpy(pkt.data + pkt.hlen, mp3_frame.raw, mp3_frame.frame_size); pkt.length = mp3_frame.frame_size; /*M Sign the packet if Openssl is activated. **/ #ifdef WITH_OPENSSL if (rsa != NULL) { if (!rtp_pkt_sign(&pkt, rsa)) { fprintf(stderr, "\nCould not sign packet\n"); return 0; } pkt.b.pt = RTP_PT_SMPA; } #endif /*M Simulate packet loss. **/ #ifdef DEBUG_PLOSS if (((random() % 100) >= ploss_rate) != 0) { #endif /* DEBUG_PLOSS */ /* send rtp packet */ if (rtp_pkt_send(&pkt, sock) < 0) { if (errno == ENOBUFS) { fprintf(stderr, "Output buffers full, waiting...\n"); } else { perror("Error while sending packet"); return 0; } } #ifdef DEBUG_PLOSS } #endif /* DEBUG_PLOSS */ /*M Set M-bit to $0$ after sending the first frame (receiver synchronisation). **/ pkt.b.m = 0; /*M Increment the MPEG Timestamp. **/ rtp_time += mp3_frame.usec; wait_time += mp3_frame.usec; /*M Sender synchronisation (\verb|sleep| until the next frame has to be sent. **/ if (wait_time > 0) usleep(wait_time); /*M Print sender information. **/ if (!quiet) { static int count = 0; if ((count++ % 10) == 0) { if (mp3_file.size > 0) { fprintf(stdout, "\r%02ld:%02ld/%02ld:%02ld %7ld/%7ld (%3ld%%) %3ldkbit/s %4ldb ", (rtp_time/1000000) / 60, (rtp_time/1000000) % 60, (long)((float)(rtp_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 60000, (long)((float)(rtp_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 1000 % 60, mp3_file.offset, mp3_file.size, (long)(100*(float)mp3_file.offset/(float)mp3_file.size), mp3_frame.bitrate, mp3_frame.frame_size); } else { fprintf(stdout, "\r%02ld:%02ld %ld %3ldkbit/s %4ldb ", (rtp_time/1000000) / 60, (rtp_time/1000000) % 60, mp3_file.offset, mp3_frame.bitrate, mp3_frame.frame_size); } } fflush(stdout); } /*M Get length of iteration. **/ gettimeofday(&tv, NULL); unsigned long len = (tv.tv_sec - start_sec) * 1000000 + (tv.tv_usec - start_usec); wait_time -= len; if (abs(wait_time) > MAX_WAIT_TIME) wait_time = 0; start_sec = tv.tv_sec; start_usec = tv.tv_usec; } /*M Close the MPEG file. **/ if (!file_close(&mp3_file)) { fprintf(stderr, "Could not close mp3 file\n"); return 0; } return 1; } /*M \emph{Print usage information.} **/ static void usage(void) { #ifdef WITH_OPENSSL fprintf(stderr, "Usage: ./poc [-s address] [-p port] [-q] [-t ttl] [-c pem] files...\n"); #else fprintf(stderr, "Usage: ./poc [-s address] [-p port] [-q] [-t ttl] files...\n"); #endif fprintf(stderr, "\t-s address : destination address (default 224.0.1.23)\n"); fprintf(stderr, "\t-p port : destination port (default 1500)\n"); fprintf(stderr, "\t-q : quiet\n"); fprintf(stderr, "\t-t ttl : multicast ttl (default 1)\n"); #ifdef WITH_OPENSSL fprintf(stderr, "\t-c pem : sign with private RSA key\n"); #endif /* WITH_OPENSSL */ #ifdef DEBUG_PLOSS fprintf(stderr, "\t-P ploss : packet loss interval\n"); #endif /* DEBUG_PLOSS */ } /*M \emph{Main server routine.} Calls the mainloop for each filename given on the command line. **/ int main(int argc, char *argv[]) { int retval = 0; char *address = NULL; unsigned short port = 1500; unsigned int ttl = 1; int quiet = 0; /*M Process the command line arguments. **/ int c; #ifdef WITH_OPENSSL while ((c = getopt(argc, argv, "hs:p:t:qc:P:")) >= 0) { #else while ((c = getopt(argc, argv, "hs:p:t:qP:")) >= 0) { #endif switch (c) { case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = (unsigned short)atoi(optarg); break; case 'q': quiet = 1; break; case 't': ttl = (unsigned int)atoi(optarg); break; /*M If Openssl is used, read in the RSA key. **/ #ifdef WITH_OPENSSL case 'c': { if (rsa != NULL) { RSA_free(rsa); rsa = NULL; } FILE *f = NULL; if (!(f = fopen(optarg, "r"))) { fprintf(stderr, "Could not open private key %s\n", optarg); retval = EXIT_FAILURE; goto exit; } if (!(rsa = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL))) { fprintf(stderr, "Could not read private key %s\n", optarg); fclose(f); retval = EXIT_FAILURE; goto exit; } fclose(f); OpenSSL_add_all_digests(); break; } #endif /* WITH_OPENSSL */ #ifdef DEBUG_PLOSS case 'P': { static struct timeval tv; gettimeofday(&tv, NULL); srandom(tv.tv_sec); ploss_rate = atoi(optarg); break; } #endif /* DEBUG_PLOSS */ case 'h': default: usage(); retval = EXIT_FAILURE; goto exit; } } if (optind == argc) { usage(); retval = EXIT_FAILURE; goto exit; } if (address == NULL) { #ifdef WITH_IPV6 if (use_ipv6) address = strdup("ff02::4"); else address = strdup("224.0.1.23"); #else address = strdup("224.0.1.23"); #endif /* WITH_IPV6 */ } if (sig_set_handler(SIGINT, sig_int) == SIG_ERR) { retval = EXIT_FAILURE; goto exit; } /*M Open the sending socket. **/ int sock; #ifdef WITH_IPV6 if (use_ipv6) sock = net_udp6_send_socket(address, port, ttl); else sock = net_udp4_send_socket(address, port, ttl); #else sock = net_udp4_send_socket(address, port, ttl); #endif /* WITH_IPV6 */ if (sock < 0) { fprintf(stderr, "Could not open socket\n"); retval = EXIT_FAILURE; goto exit; } rtp_rfc2250_pkt_init(&pkt); pkt.b.pt = RTP_PT_MPA; /*M Go through all files given on command line and stream them. **/ int i; for (i = optind; (i < argc) && !finished; i++) { assert(argv[i] != NULL); unsigned char filename[MAX_FILENAME]; strncpy(filename, argv[i], MAX_FILENAME - 1); filename[MAX_FILENAME - 1] = '\0'; if (!poc_mainloop(sock, filename, quiet)) continue; } exit: #ifdef WITH_OPENSSL if (rsa != NULL) RSA_free(rsa); #endif if (address != NULL) free(address); return retval; } poc-0.4.2/mp3cue.l0000664000175000001440000000125210165025647014317 0ustar manuelusers00000000000000%{ #include #include "mp3cue.h" #include "mp3cue-y.tab.h" extern int lc; %} %% [0-9]+ { yylval.number = atoi(yytext); return NUMBER; } [ \t] ; \r\n { lc++; return NEWLINE; } \n { lc++; return NEWLINE; } \"[^\n\"]+\" { int len = strlen(yytext) - 1; if (len > 0) yytext[len] = 0; strncpy(yylval.string, yytext+1, MP3CUE_MAX_STRING_LENGTH); return STRING; } "PERFORMER" return PERFORMER; "FILE" return FILEID; "TRACK" return TRACK; "INDEX" return INDEX; "AUDIO" return AUDIO; "TITLE" return TITLE; "CATALOG" return CATALOG; "ISRC" return ISRC; [a-zA-Z0-9]+ { strncpy(yylval.string, yytext, MP3CUE_MAX_STRING_LENGTH); return STRING; } : return COLON; %% poc-0.4.2/network6.c0000664000175000001440000001376010210123147014661 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifdef WITH_IPV6 #include "conf.h" #include #include #include #include #include #include #include #include #include #include #include #include "network.h" #include "pack.h" /*M \emph{Create an ipv6 UDP socket.} Returns the filedescriptor of the socket, or -1 on error. **/ static int net_udp6_socket(struct sockaddr_in6 *saddr, unsigned short port, unsigned int hops) { assert(saddr != NULL); /*M Create UDP socket. **/ int msock; if ((msock = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { perror("socket"); return -1; } /*M Set socket to reuse addresses. **/ int on = 1; if (setsockopt(msock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { perror("setsockopt"); goto error; } saddr->sin6_family = AF_INET6; saddr->sin6_port = htons(port); /*M If the address is a multicast address, set the TTL and turn on multicast loop so the local host can receive the UDP packets. **/ if (IN6_IS_ADDR_MULTICAST(&saddr->sin6_addr)) { unsigned int loop = 1; if ((setsockopt(msock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) < 0) || (setsockopt(msock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop)) < 0)) { perror("setsockopt"); goto error; } } return msock; error: if (close(msock) < 0) perror("close"); return -1; } /*M \emph{Create a ipv6 sending UDP socket.} Connects the created UDP socket to hostname. Returns the filedescriptor of the socket, or -1 on error. **/ int net_udp6_send_socket(char *hostname, unsigned short port, unsigned int hops) { /*M Get hostname address. **/ struct hostent *host; if (NULL == (host = gethostbyname2(hostname, AF_INET6))) { perror("gethostbyname"); return -1; } /*M Init sockaddr structure. **/ struct sockaddr_in6 saddr; memcpy(&saddr.sin6_addr, host->h_addr_list[0], (size_t)host->h_length); /*M Create udp socket. **/ int msock; if ((msock = net_udp6_socket(&saddr, port, hops)) < 0) return -1; /*M Connect to hostname. **/ if (connect(msock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("connect"); goto error; } return msock; error: if (close(msock) < 0) perror("close"); return -1; } /*M \emph{Create a receiving ipv6 UDP socket.} Binds the created UDP socket to hostname, and adds multicast membership if hostname is a multicast hostname. Returns the filedescriptor of the socket, or -1 on error. **/ int net_udp6_recv_socket(char *hostname, unsigned short port) { /*M Get hostname address. **/ struct hostent *host; if (NULL == (host = gethostbyname2(hostname, AF_INET6))) { perror("gethostbyname"); return -1; } /*M Initialize sockaddr structure. **/ struct sockaddr_in6 addr; memcpy(&addr.sin6_addr, host->h_addr_list[0], (size_t)host->h_length); /*M Create udp socket. **/ int msock; if ((msock = net_udp6_socket(&addr, port, 1)) < 0) return -1; /*M Bind to hostname. **/ if (bind(msock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); goto error; } /*M Add multicast membership if address is a multicast address. **/ if (IN6_IS_ADDR_MULTICAST(&addr.sin6_addr)) { struct ipv6_mreq mreq; memcpy(&mreq.ipv6mr_multiaddr, &addr.sin6_addr, sizeof(addr.sin6_addr)); mreq.ipv6mr_interface = 0; if (setsockopt(msock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { perror("setsockopt"); goto error; } } return msock; error: if (close(msock) < 0) perror("close"); return -1; } /*M \emph{Create a TCP v6 socket and set it non to nonblocking IO.} **/ int net_tcp6_nonblock_socket(void) { int s; s = socket(AF_INET6, SOCK_STREAM, 0); if (s == -1) return -1; if (net_tcp6_socket_nonblock(s) == -1) { close(s); return -1; } return s; } int net_tcp6_socket_nonblock(int s) { if (fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0) | O_NONBLOCK) == -1) return -1; return 0; } /*M \emph{Bind a socket to an IPV4 adress and port.} **/ int net_tcp6_bind(int s, unsigned char ip[16], unsigned short port) { struct sockaddr_in6 sa; memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; unsigned char *ptr = (unsigned char *)&sa.sin6_port; UINT16_PACK(ptr, port); memcpy(&sa.sin6_addr, ip, 16); return bind(s, (struct sockaddr *)&sa, sizeof(sa)); } int net_tcp6_bind_reuse(int s, unsigned char ip[16], unsigned short port) { int opt = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); return net_tcp6_bind(s, ip, port); } int net_tcp6_listen_socket(char *hostname, unsigned short port) { /*M Get hostname address. **/ struct hostent *host; if (NULL == (host = gethostbyname2(hostname, AF_INET6))) { perror("gethostbyname"); return -1; } if (host->h_length != 16) { perror("gethostbyname"); return -1; } int sock; if (((sock = net_tcp6_nonblock_socket()) < 0) || (net_tcp6_bind_reuse(sock, host->h_addr_list[0], port) < 0) || (listen(sock, 16) < 0)) { return -1; } return sock; } int net_tcp6_accept_socket(int s, unsigned char ip[16], unsigned short *port) { struct sockaddr_in6 sa; int len = sizeof(sa); int fd; fd = accept(s, (struct sockaddr *)&sa, &len); if (fd == -1) return -1; memcpy(ip, (unsigned char *)&sa.sin6_addr, 16); unsigned char *ptr = (unsigned char *)&sa.sin6_port; *port = UINT16_UNPACK(ptr); return fd; } #endif /*M **/ poc-0.4.2/id3.c0000664000175000001440000001041310203140663013555 0ustar manuelusers00000000000000/* * id3v2 routines * * (c) 2005 bl0rg.net */ #include "conf.h" #include #include #include #include #include "file.h" #include "pack.h" #include "id3.h" /* create a sync safe integer (bit 7 is 0) */ static unsigned long id3_sync_safe(unsigned long num) { unsigned long res = 0; int i; for (i = 0; i < 4; i++) { res |= (num & 0x7F) << (i * 8); num >>= 7; } return res; } unsigned int id3_fill_comment(unsigned char *buf, unsigned int len, unsigned char encoding, unsigned char *short_comment, unsigned char *long_comment, unsigned char *language) { assert(buf != NULL); assert(len > 0); if ((short_comment == NULL) && (long_comment == NULL)) return 0; if (language == NULL) language = "eng"; unsigned int short_len = short_comment ? strlen(short_comment) : 0; unsigned int long_len = long_comment ? strlen(long_comment) : 0; unsigned char *ptr = buf; unsigned int flen = 1 + 3 + short_len + 1 + long_len + 1; if (len < 6 + flen) return 0; memcpy(ptr, "COM", 3); ptr += 3; UINT24_PACK(ptr, id3_sync_safe(flen)); UINT8_PACK(ptr, encoding); memcpy(ptr, language, 3); ptr += 3; if (short_comment) { memcpy(ptr, short_comment, short_len); ptr += short_len; } UINT8_PACK(ptr, 0x00); if (long_comment) { memcpy(ptr, long_comment, long_len); ptr += long_len; } UINT8_PACK(ptr, 0x00); return 6 + flen; } unsigned int id3_fill_tframe(unsigned char *buf, unsigned int len, unsigned char *type, unsigned char encoding, unsigned char *string) { assert(buf != NULL); assert(len > 0); assert(type != NULL); assert(string != NULL); unsigned char *ptr = buf; unsigned int slen = strlen(string); unsigned int flen = slen + 2; if (len < 6 + flen) return 0; memcpy(ptr, type, 3); ptr += 3; UINT24_PACK(ptr, id3_sync_safe(flen)); UINT8_PACK(ptr, encoding); memcpy(ptr, string, slen); ptr += slen; UINT8_PACK(ptr, 0x00); return flen + 6; } int id3_fill_header(unsigned char *buf, unsigned int len, unsigned long id3_size) { assert(buf != NULL); assert(len > 0); if (len < 10) return 0; unsigned char *ptr = buf; memcpy(ptr, "ID3", 3); ptr += 3; UINT8_PACK(ptr, 0x02); UINT8_PACK(ptr, 0x00); /* version 2.0 */ UINT8_PACK(ptr, 0x00); UINT32_PACK(ptr, id3_sync_safe(id3_size)); return 10; } int id3_write_tag(file_t *outfile, unsigned char *album_title, unsigned char *artist, unsigned char *title, unsigned int track_number, unsigned char *comment) { /* write id3 tags */ unsigned char id3[ID3_TAG_SIZE]; unsigned char *ptr = id3 + ID3_HEADER_SIZE; unsigned int size = 0, bytes_left = sizeof(id3) - ID3_HEADER_SIZE; unsigned int len; if (album_title && strlen(album_title) > 0) { len = id3_fill_tframe(ptr, bytes_left, "TAL", 0, album_title); if (len == 0) return 0; bytes_left -= len; ptr += len; size += len; } if (artist && strlen(artist) > 0) { len = id3_fill_tframe(ptr, bytes_left, "TP1", 0, artist); if (len == 0) return 0; bytes_left -= len; ptr += len; size += len; } if (title && strlen(title) > 0) { len = id3_fill_tframe(ptr, bytes_left, "TT2", 0, title); if (len == 0) return 0; bytes_left -= len; ptr += len; size += len; } if (track_number > 0) { unsigned char tracknumber[256]; snprintf(tracknumber, 256, "%d", track_number); len = id3_fill_tframe(ptr, bytes_left, "TRK", 0, tracknumber); if (len == 0) return 0; bytes_left -= len; ptr += len; size += len; } if (comment && strlen(comment) > 0) { len = id3_fill_comment(ptr, bytes_left, 0, NULL, comment, "eng"); if (len == 0) return 0; bytes_left -= len; ptr += len; size += len; } if (id3_fill_header(id3, sizeof(id3), size) == 0) return 0; len = file_write(outfile, id3, size + ID3_HEADER_SIZE); if (len != size + ID3_HEADER_SIZE) return 0; return 1; } poc-0.4.2/mp3-trans.c0000664000175000001440000000260410210123147014721 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include "mp3.h" int mp3_trans_frame(mp3_frame_t *frame) { assert(frame != NULL); unsigned int i; for (i = 0; i < 2; i++) { unsigned int j; for (j = 0; j < 4; j++) frame->si.channel[i].scfsi[j] = 1; } return 1; } #ifdef MP3_TEST int main(int argc, char *argv[]) { char *f[2]; if (!(f[0] = *++argv) || !(f[1] = *++argv)) { fprintf(stderr, "Usage: mp3-write mp3in mp3out\n"); return 1; } mp3_file_t in; if (!mp3_open_read(&in, f[0])) { fprintf(stderr, "Could not open mp3 file for read: %s\n", f[0]); return 1; } mp3_file_t out; if (!mp3_open_write(&out, f[1])) { fprintf(stderr, "Could not open mp3 file for write: %s\n", f[1]); mp3_close(&in); return 1; } mp3_frame_t frame; while (mp3_next_frame(&in, &frame) > 0) { memset(frame.raw, 0, 4 + frame.si_size); if (!mp3_trans_frame(&frame)) { fprintf(stderr, "Could not transform frame\n"); mp3_close(&in); mp3_close(&out); return 1; } if (!mp3_fill_hdr(&frame) || !mp3_fill_si(&frame) || (mp3_write_frame(&out, &frame) <= 0)) { fprintf(stderr, "Could not write frame\n"); mp3_close(&in); mp3_close(&out); return 1; } } mp3_close(&in); mp3_close(&out); return 0; } #endif poc-0.4.2/pob-2250-rb.c0000664000175000001440000002166510214014115014652 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include #ifdef NEED_GETOPT_H__ #include #endif /* NEED_GETOPT_H__ */ #ifdef WITH_OPENSSL #include #include #include #include #endif /* WITH_OPENSSL */ #include "rtp.h" #include "rtp-rb.h" #include "network.h" #ifdef WITH_OPENSSL RSA *rsa = NULL; #endif #define RTP_MINSLEEP 20000 /* 200 ms */ /*M \emph{Structure to hold client accounting information.} This is used to count the number of wrong packets, duplicate packets, out of order packets, unauthenticated packets. **/ typedef struct pob_stat_s { /*M Number of packets received. **/ unsigned int rcvd_pkts; /*M Number of out of order packets received. **/ unsigned int ooo_pkts; /*M Number of duplicated packets received. **/ unsigned int dup_pkts; /*M Number of bad packets received. **/ unsigned int bad_pkts; #ifdef WITH_OPENSSL /*M Badly signed packets. **/ unsigned int sign_pkts; #endif /*M Number of buffer overflows. **/ unsigned int buf_ofs; /*M Number of buffer underflows. **/ unsigned int buf_ufs; } pob_stat_t; static pob_stat_t pob_stats = { 0, 0, 0, 0, 0 #ifdef WITH_OPENSSL ,0 #endif }; /*M \emph{Timestamp of last played packet.} **/ static unsigned long tstamp_last = 0; /*M **/ int pob_insert_pkt(rtp_pkt_t *pkt) { assert(pkt != NULL); /*M We have received a packet. **/ pob_stats.rcvd_pkts++; /*M Verify packet if Openssl is activated. **/ #ifdef WITH_OPENSSL if (rsa) { if ((pkt->b.pt != RTP_PT_SMPA) || !rtp_pkt_verify(pkt, rsa)) { pob_stats.sign_pkts++; return 0; } } #endif int num = 0; /* insert packet into ringbuffer */ if (rtp_rb_length() > 0) { /* get index of first packet */ rtp_pkt_t *firstpkt = rtp_rb_first(); assert(firstpkt != NULL); assert(firstpkt->length != 0); num = net_seqnum_diff(firstpkt->b.seq, pkt->b.seq, 1 << 16); } if (!rtp_rb_insert_pkt(pkt, num)) { #ifdef DEBUG fprintf(stderr, "ring buffer full\n"); #endif rtp_rb_clear(); tstamp_last = pkt->timestamp; return pob_insert_pkt(pkt); } else { return 1; } } int pob_recv_pkt(int sock, rtp_pkt_t *pkt) { struct timeval t_out; t_out.tv_sec = 0; t_out.tv_usec = RTP_MINSLEEP; fd_set fds; FD_ZERO(&fds); FD_SET(sock, &fds); /*M Wait for network input or for timeout. **/ int ret = select(sock + 1, &fds, NULL, NULL, &t_out); /*M Check for interrupted system call. **/ if (ret == -1) { if ((errno == EINTR) || (errno == EAGAIN)) { return 0; } else { perror("select"); return -1; } } /*M If there is network input, read incoming packet. **/ if (FD_ISSET(sock, &fds)) { rtp_rfc2250_pkt_init(pkt); if (rtp_pkt_read(pkt, sock) <= 0) { return -1; } else { return 1; } } return 0; } /*M \emph{Simple RTP RFC2250 streaming client main loop.} The mainloop calls the prebuffering routine each time the receiving list is empty, then receives packets and writes the packets in the buffering queue out to standard output. **/ int pob_mainloop(int sock, int quiet) { int retval = 0; int finished = 0; while (!finished) { static int prebuffering = 0; rtp_pkt_t pkt; if (rtp_rb_cnt == 0) { prebuffering = 1; } /*M Receive next packet. */ switch (pob_recv_pkt(sock, &pkt)) { case 0: break; case -1: finished = 1; continue; default: /*M Insert new packet into the buffering list. **/ switch (pob_insert_pkt(&pkt)) { case -1: retval = 0; goto exit; default: break; } break; } static unsigned long time_last; unsigned long time_now; struct timeval tv; gettimeofday(&tv, NULL); time_now = tv.tv_sec * 90000 + (unsigned long)(tv.tv_usec / 11.111); if (prebuffering == 1) { if (rtp_rb_cnt >= (rtp_rb_size / 2)) { rtp_pkt_t *firstpkt = rtp_rb_first(); assert(firstpkt != NULL); assert(firstpkt->length != 0); tstamp_last = firstpkt->timestamp; time_last = time_now; prebuffering = 0; if (!quiet) fprintf(stderr, "\n"); } else { /*M Print prebuffering information. **/ if (!quiet) fprintf(stderr, "Prebuffering: %.2f%%\r", (float)rtp_rb_cnt / (rtp_rb_size / 2.0) * 100.0); continue; } } /*M Print client information. **/ if (!quiet) { static int count = 0; if ((count++ % 10) == 0) { fprintf(stderr, "pkts: %.8u\tdups: %.6u\tdrop: %.6u\tbuf: %.6u len:%.6u\t\r", pob_stats.rcvd_pkts, pob_stats.dup_pkts, pob_stats.ooo_pkts, rtp_rb_cnt, rtp_rb_length()); } } #ifdef DEBUG rtp_rb_print(); #endif unsigned long tstamp_now = tstamp_last + (time_now - time_last); while (rtp_rb_length() > 0) { rtp_pkt_t *pkt = rtp_rb_first(); assert(pkt != NULL); if (pkt->length != 0) { /* boeser hack XXX */ if (pkt->timestamp > (tstamp_now + 3000)) break; if (write(STDOUT_FILENO, pkt->data + pkt->hlen, pkt->length) < (int)pkt->length) { fprintf(stderr, "Error writing to stdout\n"); retval = 0; goto exit; } } rtp_rb_pop(); } } exit: return retval; } /*M \emph{Print RFC2250 RTP client usage.} **/ static void usage(void) { fprintf(stderr, "Usage: ./pob [-s address] [-p port] [-b size] [-q]"); #ifdef WITH_OPENSSL fprintf(stderr, "[-c cert]"); #endif fprintf(stderr, "\n"); fprintf(stderr, "\t-s address : destination address (default 0.0.0.0)\n"); fprintf(stderr, "\t-p port : destination port (default 1500)\n"); fprintf(stderr, "\t-b size : maximal number of packets in buffer (default 128)\n"); fprintf(stderr, "\t-q : quiet\n"); #ifdef WITH_OPENSSL fprintf(stderr, "\t-c cert : verify packets with rsa certificate\n"); #endif } /*M \emph{RFC2250 RTP client entry routine.} **/ int main(int argc, char *argv[]) { char *address = NULL; unsigned short port = 1500; unsigned int buffer_size = 128; int retval = EXIT_SUCCESS, quiet = 0; #ifdef WITH_OPENSSL X509 *x509 = NULL; EVP_PKEY *pkey = NULL; #endif /*M Process the command line arguments. **/ int c; while ((c = getopt(argc, argv, "hs:p:b:t:q" #ifdef WITH_OPENSSL "c:" #endif )) >= 0) { switch (c) { case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = atoi(optarg); break; case 'b': buffer_size = (unsigned short)atoi(optarg); break; case 'q': quiet = 1; break; /*M If Openssl is used, read in the RSA certificate. **/ #ifdef WITH_OPENSSL case 'c': { FILE *f; if (x509) { X509_free(x509); x509 = NULL; } if (pkey) { EVP_PKEY_free(pkey); pkey = NULL; rsa = NULL; } if (!(f = fopen(optarg, "r")) || !PEM_read_X509(f, &x509, NULL, NULL) || !(pkey = X509_get_pubkey(x509))) { fprintf(stderr, "Could not read certificate %s\n", optarg); if (f) fclose(f); retval = EXIT_FAILURE; goto exit; } fclose(f); if (pkey->type != EVP_PKEY_RSA) { fprintf(stderr, "Key is not a RSA key\n"); retval = EXIT_FAILURE; goto exit; } rsa = pkey->pkey.rsa; break; } #endif case 'h': default: usage(); retval = EXIT_SUCCESS; goto exit; } } /*M Initialize the ring buffer. **/ rtp_rb_init(buffer_size); if (address == NULL) { #ifdef WITH_IPV6 address = strdup("ff02::4"); #else address = strdup("0.0.0.0"); #endif /* WITH_IPV6 */ } /*M Create the receiving socket. **/ int sock; #ifdef WITH_IPV6 sock = net_udp6_recv_socket(address, port); #else sock = net_udp4_recv_socket(address, port); #endif /* WITH_IPV6 */ if (sock < 0) { fprintf(stderr, "Could not open socket\n"); retval = EXIT_FAILURE; goto exit; } if (!pob_mainloop(sock, quiet)) retval = EXIT_FAILURE; if (close(sock) < 0) perror("close"); exit: rtp_rb_destroy(); #ifdef WITH_OPENSSL if (pkey) EVP_PKEY_free(pkey); if (x509) X509_free(x509); #endif if (address != NULL) free(address); return retval; } /*C **/ poc-0.4.2/crc32.c0000664000175000001440000000234410210123147014012 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include "crc32.h" void crc32_init(crc32_t *crc, unsigned long poly, unsigned long init, unsigned long xor) { crc->poly = poly; crc->init = init; crc->xor = xor; int i; for (i = 0; i < 256; i++) { unsigned long r = (unsigned long)i; r <<= 24; int j; for (j = 0; j < 8; j++) { unsigned long bit = r & (1 << 31); r <<= 1; if (bit) r ^= crc->poly; } r &= 0xFFFFFFFF; crc->table[i] = r; } } unsigned long crc32(crc32_t *crc, unsigned char *data, unsigned long len) { unsigned long r = crc->init; unsigned char *ptr = data; while (len--) r = (r << 8) ^ crc->table[(r >> 24) ^ *ptr++]; r ^= crc->xor; r &= 0xFFFFFFFF; return r; } #ifdef CRC32_TEST #include #include static void usage(void) { fprintf(stderr, "Usage: ./crc32test polynom messagestring\n"); } int main(int argc, char *argv[]) { if (argc != 3) { usage(); return 1; } unsigned long poly; sscanf(argv[1], "%lx", &poly); crc32_t crc; crc32_init(&crc, poly, 0, 0); printf("crc: %lx\n", crc32(&crc, argv[2], strlen(argv[2]))); return 0; } #endif /* CRC32_TEST */ /*C **/ poc-0.4.2/poc-fec.c0000664000175000001440000002361610214014115014415 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #ifdef NEED_GETOPT_H__ #include #endif #include #include #include #include #include #include #include #include #include "mp3.h" #include "network.h" #include "fec-pkt.h" #include "fec.h" #include "pack.h" #include "aq.h" #include "signal.h" #ifdef WITH_IPV6 static int use_ipv6 = 0; #endif /* WITH_IPV6 */ #define MAX_FILENAME 256 #ifdef DEBUG_PLOSS int ploss_rate = 20; #endif /* DEBUG_PLOSS */ /*M \emph{Maximal synchronization latency for sending packets.} In usecs. **/ #define MAX_WAIT_TIME (1 * 1000 * 1000) static int finished = 0; int quiet = 0; unsigned char fec_k = 20; unsigned char fec_n = 25; fec_pkt_t pkt; static void sig_int(int signo) { finished = 1; } /*M **/ int poc_encoder(int sock, struct sockaddr_in *saddr, char *filename) { int retval = 1; /*M Open file for reading. **/ file_t mp3_file; if (!file_open_read(&mp3_file, filename)) { fprintf(stderr, "Could not open mp3 file: %s\n", filename); return 0; } /*M Initialize the FEC parameters. **/ fec_t *fec = fec_new(fec_k, fec_n); aq_t adu_queue; aq_init(&adu_queue); adu_t *in_adus[fec_k]; unsigned int cnt = 0; static long wait_time = 0; unsigned long fec_time = 0; unsigned long fec_time2 = 0; /*M Get start time. **/ struct timeval tv; gettimeofday(&tv, NULL); unsigned long start_sec, start_usec; start_sec = tv.tv_sec; start_usec = tv.tv_usec; /*M Get next MP3 frame and queue it into the ADU queue. **/ mp3_frame_t mp3_frame; while ((mp3_next_frame(&mp3_file, &mp3_frame) > 0) && !finished) { if (aq_add_frame(&adu_queue, &mp3_frame) > 0) { /* a new ADU has been produced */ in_adus[cnt] = aq_get_adu(&adu_queue); assert(in_adus[cnt] != NULL); /* check if the FEC group is complete */ if (++cnt == fec_k) { unsigned int max_len = 0; unsigned long group_duration = 0; int i; for (i = 0; i < fec_k; i++) { unsigned int adu_len = mp3_frame_size(in_adus[i]); if (adu_len > max_len) max_len = adu_len; group_duration += in_adus[i]->usec; } fec_time += group_duration; assert(max_len < FEC_PKT_PAYLOAD_SIZE); /* Encode the FEC group */ unsigned char *in_ptrs[fec_k]; unsigned char buf[fec_k * max_len]; unsigned char *ptr = buf; unsigned long bitrate = 0; for (i = 0; i < fec_k; i++) { unsigned int adu_len = mp3_frame_size(in_adus[i]); in_ptrs[i] = ptr; memcpy(ptr, in_adus[i]->raw, adu_len); if (adu_len < max_len) memset(ptr + adu_len, 0, max_len - adu_len); ptr += max_len; bitrate += in_adus[i]->bitrate; } bitrate /= fec_k; for (i = 0; i < fec_n; i++) { pkt.hdr.packet_seq = i; pkt.hdr.fec_k = fec_k; pkt.hdr.fec_n = fec_n; pkt.hdr.fec_len = max_len + 2; pkt.hdr.group_tstamp = fec_time; fec_encode(fec, in_ptrs, pkt.payload, i, max_len); if (i < fec_k) { pkt.hdr.len = mp3_frame_size(in_adus[i]); } else { pkt.hdr.len = max_len; } /*M Simulate packet loss. **/ #ifdef DEBUG_PLOSS if ((random() % 100) >= ploss_rate ) { #endif /* DEBUG_PLOSS */ #ifdef DEBUG fprintf(stderr, "sending fec packet group stamp %ld, gseq %d, pseq %d, size %d\n", pkt.hdr.group_tstamp, pkt.hdr.group_seq, pkt.hdr.packet_seq, pkt.hdr.len); #endif /* send rtp packet */ if (fec_pkt_sendto(&pkt, sock, (struct sockaddr *)saddr, sizeof(*saddr)) < 0) { if (errno == ENOBUFS) { fprintf(stderr, "Output buffers full, waiting...\n"); } else { perror("Error while sending packet"); retval = 0; goto exit; } } #ifdef DEBUG_PLOSS } #endif /* DEBUG_PLOSS */ /*M Update the time we have to wait. **/ wait_time += (group_duration / fec_n); fec_time2 += (group_duration / fec_n); /*M Sender synchronisation (\verb|sleep| until the next packet has to be sent. **/ if (wait_time > 1000) usleep(wait_time); if (!quiet) { static unsigned int count = 0; if ((count++ % 10) == 0) { if (mp3_file.size > 0) { fprintf(stdout, "\r%02ld:%02ld/%02ld:%02ld %7ld/%7ld %3ldkbit/s (%3ld%%) ", (fec_time2/1000000) / 60, (fec_time2/1000000) % 60, (long)((float)(fec_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 60000, (long)((float)(fec_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 1000 % 60, mp3_file.offset, mp3_file.size, bitrate, (long)(100*(float)mp3_file.offset/(float)mp3_file.size)); } else { fprintf(stdout, "\r%02ld:%02ld %ld %3ldkbit/s ", (fec_time2/1000000) / 60, (fec_time2/1000000) % 60, mp3_file.offset, bitrate); } fflush(stdout); } } /*M Get length of iteration. **/ gettimeofday(&tv, NULL); unsigned long len = (tv.tv_sec - start_sec) * 1000000 + (tv.tv_usec - start_usec); wait_time -= len; if (abs(wait_time) > MAX_WAIT_TIME) wait_time = 0; start_sec = tv.tv_sec; start_usec = tv.tv_usec; } pkt.hdr.group_seq++; for (i = 0; i < fec_k; i++) free(in_adus[i]); cnt = 0; } } } int i; exit: for (i = 0; i < cnt; i++) free(in_adus[i]); aq_destroy(&adu_queue); fec_free(fec); file_close(&mp3_file); return retval; } /*M \emph{Print usage information.} **/ static void usage(void) { fprintf(stderr, "Usage: ./poc-fec [-s address] [-p port] [-k fec_k] [-n fec_n] [-q] [-t ttl]"); #ifdef WITH_IPV6 fprintf(stderr, " [-6]"); #endif /* WITH_IPV6 */ fprintf(stderr, " files...\n"); fprintf(stderr, "\t-s address : destination address (default 224.0.1.23 or ff02::4)\n"); fprintf(stderr, "\t-p port : destination port (default 1500)\n"); fprintf(stderr, "\t-q : quiet\n"); fprintf(stderr, "\t-t ttl : multicast ttl (default 1)\n"); fprintf(stderr, "\t-k fec_k : FEC k parameter (default 20)\n"); fprintf(stderr, "\t-n fec_n : FEC n parameter (default 25)\n"); #ifdef WITH_IPV6 fprintf(stderr, "\t-6 : use ipv6\n"); #endif /* WITH_IPV6 */ } /*M \emph{Main server routine.} Calls the mainloop for each filename given on the command line. **/ int main(int argc, char *argv[]) { int retval = 0; char *address = NULL; unsigned short port = 1500; unsigned int ttl = 1; /*M Process the command line arguments. **/ int c; while ((c = getopt(argc, argv, "hs:p:t:qP:k:n:" #ifdef WITH_IPV6 "6" #endif /* WITH_IPV6 */ )) >= 0) { switch (c) { #ifdef WITH_IPV6 case '6': use_ipv6 = 1; break; #endif /* WITH_IPV6 */ case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = (unsigned short)atoi(optarg); break; case 'q': quiet = 1; break; case 't': ttl = (unsigned int)atoi(optarg); break; case 'k': fec_k = (unsigned int)atoi(optarg); break; case 'n': fec_n = (unsigned int)atoi(optarg); break; #ifdef DEBUG_PLOSS case 'P': { static struct timeval tv; gettimeofday(&tv, NULL); srandom(tv.tv_sec); ploss_rate = atoi(optarg); break; } #endif /* DEBUG_PLOSS */ case 'h': default: usage(); retval = EXIT_FAILURE; goto exit; } } if (fec_n <= fec_k) { fprintf(stderr, "fec_n must be bigger than fec_k\n"); retval = EXIT_FAILURE; goto exit; } if (optind == argc) { usage(); retval = EXIT_FAILURE; goto exit; } if (address == NULL) { #ifdef WITH_IPV6 if (use_ipv6) address = strdup("ff02::4"); else address = strdup("224.0.1.23"); #else address = strdup("224.0.1.23"); #endif /* WITH_IPV6 */ } if (sig_set_handler(SIGINT, sig_int) == SIG_ERR) { retval = EXIT_FAILURE; goto exit; } /*M Open the sending socket. **/ int sock; struct sockaddr_in saddr; if (!net_ip4_resolve_hostname(address, port, NULL, &saddr)) { fprintf(stderr, "Could not resolve %s\n", address); retval = EXIT_FAILURE; goto exit; } sock = net_udp4_socket(&saddr, port, ttl); if (sock < 0) { fprintf(stderr, "Could not open socket\n"); retval = EXIT_FAILURE; goto exit; } fec_pkt_init(&pkt); /*M Go through all files given on command line and stream them. **/ int i; for (i = optind; (i < argc) && !finished; i++) { assert(argv[i] != NULL); unsigned char filename[MAX_FILENAME]; strncpy(filename, argv[i], MAX_FILENAME - 1); filename[MAX_FILENAME - 1] = '\0'; if (!poc_encoder(sock, &saddr, filename)) continue; } exit: if (address != NULL) free(address); return retval; } /*M */ poc-0.4.2/vorbis-read.c0000664000175000001440000001370110210123147015312 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include "ogg.h" #include "file.h" #include "vorbis.h" #include "buf.h" #include "pack.h" #include "bv.h" #ifdef DEBUG void vorbis_stream_print(vorbis_stream_t *vorbis) { fprintf(stderr, "audio channels: %d, sample_rate: %lu\n", vorbis->audio_channels, vorbis->audio_sample_rate); fprintf(stderr, "bitrate max: %lu, nominal: %lu, min: %lu\n", vorbis->bitrate_maximum, vorbis->bitrate_nominal, vorbis->bitrate_minimum); fprintf(stderr, "blocksize 0: %d, blocksize 1: %d\n", vorbis->blocksize_0, vorbis->blocksize_1); } #endif /* DEBUG */ /*M \emph{Unpack the Vorbis identification header and check it is correct.} **/ int vorbis_unpack_id_hdr(vorbis_stream_t *vorbis) { assert(vorbis != NULL); assert(vorbis->id_hdr.data != NULL); assert(vorbis->id_hdr.len == VORBIS_ID_HDR_SIZE); unsigned char *ptr = vorbis->id_hdr.data + VORBIS_HDR_SIZE; vorbis->vorbis_version = LE_UINT32_UNPACK(ptr); vorbis->audio_channels = UINT8_UNPACK(ptr); vorbis->audio_sample_rate = LE_UINT32_UNPACK(ptr); vorbis->bitrate_maximum = LE_UINT32_UNPACK(ptr); vorbis->bitrate_nominal = LE_UINT32_UNPACK(ptr); vorbis->bitrate_minimum = LE_UINT32_UNPACK(ptr); bv_t bv; bv_init(&bv, ptr, 8); vorbis->blocksize_1 = bv_get_bits(&bv, 4); vorbis->blocksize_0 = bv_get_bits(&bv, 4); #ifdef DEBUG vorbis_stream_print(vorbis); #endif /* DEBUG */ if ((vorbis->vorbis_version != 0) || (vorbis->audio_channels == 0) || (vorbis->audio_sample_rate == 0) || (vorbis->blocksize_0 > vorbis->blocksize_1)) return 0; return 1; } /*M \emph{Read the packet data in the OGG page beginning at segment \verb|vorbis->segment|, and append it to the buffer \verb|packet|. **/ int vorbis_packet_in_page(vorbis_stream_t *vorbis, ogg_page_t *page, buf_t *packet) { for (; vorbis->segment < page->page_segments; vorbis->segment++) { if (page->lacing_values[vorbis->segment] > 0) { buf_append(packet, ogg_segment(page, vorbis->segment), page->lacing_values[vorbis->segment]); } if (page->lacing_values[vorbis->segment] < 255) { vorbis->segment++; return 1; } } /*M Not enough segments for complete packet. **/ return 0; } /*M \emph{Read the next Vorbis packet from an OGG stream.} **/ int vorbis_next_packet(vorbis_stream_t *vorbis, buf_t *packet) { assert(vorbis != NULL); assert(packet != NULL); assert(packet->data != NULL); packet->len = 0; /*M Check if we have to read in a new page. **/ if (vorbis->segment >= vorbis->page.page_segments) { if (!ogg_next_page(&vorbis->file, &vorbis->page)) return 0; vorbis->segment = 0; } again: if (vorbis_packet_in_page(vorbis, &vorbis->page, packet)) return 1; /*M Not enough segments for complete packet in page, read a new page and hope it is a continuation page. **/ if (!ogg_next_page(&vorbis->file, &vorbis->page)) return 0; vorbis->segment = 0; /*M Check if the next page is a continuation page. **/ if (vorbis->page.b.continuation == 0) { fprintf(stderr, "Subsequent page was not continuation page.\n"); return 0; } goto again; } /*M \emph{Read the Vorbis headers from an OGG stream.} **/ int vorbis_stream_read_hdrs(vorbis_stream_t *vorbis) { assert(vorbis != NULL); /*M Read in the first OGG page which should contain only one segment containing the Vorbis identification header. **/ if (!ogg_next_page(&vorbis->file, &vorbis->hdr_pages[0])) return 0; if (vorbis->hdr_pages[0].page_segments > 1) return 0; if (!vorbis_packet_in_page(vorbis, vorbis->hdr_pages, &vorbis->id_hdr) || !vorbis_check_packet(&vorbis->id_hdr, 1) || !vorbis_unpack_id_hdr(vorbis)) return 0; int i = 1; /* read next page containing start of comment header */ if (!ogg_next_page(&vorbis->file, vorbis->hdr_pages + i)) return 0; vorbis->segment = 0; while (i < VORBIS_MAX_HDR_PAGES) { if (!vorbis_packet_in_page(vorbis, vorbis->hdr_pages + i, &vorbis->comment_hdr)) { i++; if (!ogg_next_page(&vorbis->file, vorbis->hdr_pages + i)) return 0; vorbis->segment = 0; } else { if (!vorbis_check_packet(&vorbis->comment_hdr, 3)) return 0; break; } } if (i == VORBIS_MAX_HDR_PAGES) return 0; while (i < VORBIS_MAX_HDR_PAGES) { if (!vorbis_packet_in_page(vorbis, vorbis->hdr_pages + i, &vorbis->setup_hdr)) { i++; if (!ogg_next_page(&vorbis->file, vorbis->hdr_pages + i)) return 0; vorbis->segment = 0; } else { if (!vorbis_check_packet(&vorbis->setup_hdr, 5)) return 0; /* must be the last segment in packet */ if (vorbis->segment < (vorbis->hdr_pages[i].page_segments)) return 0; break; } } vorbis->hdr_pages_cnt = i + 1; return 1; } /*C **/ #ifdef VORBIS_TEST #include int main(int argc, char *argv[]) { int retval = EXIT_SUCCESS; char *f; if (!(f = *++argv)) { fprintf(stderr, "Usage: vorbistest oggfile\n"); return 1; } ogg_init(); vorbis_stream_t vorbis; vorbis_stream_init(&vorbis); buf_t packet; packet.len = 0; packet.size = 0; packet.data = NULL; buf_alloc(&packet, 512); if (!file_open_read(&vorbis.file, f)) { fprintf(stderr, "Could not open ogg file: %s\n", f); retval = EXIT_FAILURE; goto exit; } if (!vorbis_stream_read_hdrs(&vorbis)) { fprintf(stderr, "Stream is not a OGG encapsulated Vorbis stream\n"); retval = EXIT_FAILURE; goto exit; } while (vorbis_next_packet(&vorbis, &packet) > 0) { fprintf(stderr, "Packet length: %lu, size %lu\n", packet.len, packet.size); fgetc(stdin); } file_close(&vorbis.file); exit: vorbis_stream_destroy(&vorbis); buf_free(&packet); return retval; } #endif /* VORBIS_TEST */ poc-0.4.2/network4.c0000664000175000001440000001471010214014115014651 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include #include #include #include #include "network.h" #include "pack.h" /* * Resolve an IP4 hostname (XXX IP6 support later). */ int net_ip4_resolve_hostname(const char *hostname, unsigned short port, unsigned char ip[4], struct sockaddr_in *saddr) { assert(hostname != NULL); struct hostent *host; if (NULL == (host = gethostbyname(hostname))) { perror("gethostbyname"); return 0; } if (host->h_length != 4) { return 0; } if (ip != NULL) memcpy(ip, host->h_addr_list[0], host->h_length); if (saddr != NULL) { memcpy(&saddr->sin_addr, host->h_addr_list[0], host->h_length); saddr->sin_port = port; } return 1; } /*M \emph{Create an UDP socket.} If the given address is a multicast adress, the socket will be set to use the multicast TTL ttl and sets the datagrams to loop back. Returns the filedescriptor of the socket, or -1 on error. **/ int net_udp4_socket(struct sockaddr_in *saddr, unsigned short port, unsigned char ttl) { assert(saddr != NULL); /*M Create UDP socket. **/ int fd; if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return -1; } /*M Set socket to reuse addresses. **/ int on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { perror("setsockopt"); goto error; } { static int allow = 1; if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&allow, sizeof(allow)) == -1) { perror("setsockopt"); goto error; } } saddr->sin_family = AF_INET; saddr->sin_port = htons(port); /*M If the address is a multicast address, set the TTL and turn on multicast loop so the local host can receive the UDP packets. **/ if (IN_MULTICAST(htonl(saddr->sin_addr.s_addr))) { unsigned char loop = 1; if ((setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) || (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0)) { perror("setsockopt"); goto error; } } return fd; error: if (close(fd) < 0) perror("close"); return -1; } /*M \emph{Create a sending UDP socket.} Connects the created UDP socket to hostname. Returns the filedescriptor of the socket, or -1 on error. **/ int net_udp4_send_socket(char *hostname, unsigned short port, unsigned char ttl) { struct sockaddr_in saddr; if (!net_ip4_resolve_hostname(hostname, port, NULL, &saddr)) return -1; /*M Create udp socket. **/ int fd; if ((fd = net_udp4_socket(&saddr, port, ttl)) < 0) return -1; if (saddr.sin_addr.s_addr == INADDR_BROADCAST) { static int allow = 1; if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&allow, sizeof(allow)) == -1) { perror("setsockopt"); goto error; } } /*M Connect to hostname. **/ if (connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("connect"); goto error; } return fd; error: if (close(fd) < 0) perror("close"); return -1; } /*M \emph{Create a receiving UDP socket.} Binds the created UDP socket to hostname, and adds multicast membership if hostname is a multicast hostname. Returns the filedescriptor of the socket, or -1 on error. **/ int net_udp4_recv_socket(char *hostname, unsigned short port) { struct sockaddr_in addr; if (!net_ip4_resolve_hostname(hostname, port, NULL, &addr)) memset(&addr.sin_addr, 0, sizeof(addr.sin_addr)); /*M Create udp socket. **/ int fd; if ((fd = net_udp4_socket(&addr, port, 1)) < 0) return -1; /*M Bind to hostname. **/ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); goto error; } /*M Add multicast membership if address is a multicast address. **/ if (IN_MULTICAST(htonl(addr.sin_addr.s_addr))) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = addr.sin_addr.s_addr; mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { perror("setsockopt"); goto error; } } return fd; error: if (close(fd) < 0) perror("close"); return -1; } /*M \emph{Create a TCP v4 socket and set it non to nonblocking IO.} **/ int net_tcp4_nonblock_socket(void) { int s; s = socket(AF_INET, SOCK_STREAM, 0); if (s == -1) return -1; if (net_tcp4_socket_nonblock(s) == -1) { close(s); return -1; } return s; } int net_tcp4_socket_nonblock(int s) { if (fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0) | O_NONBLOCK) == -1) return -1; return 0; } /*M \emph{Bind a socket to an IPV4 adress and port.} **/ int net_tcp4_bind(int s, unsigned char ip[4], unsigned short port) { struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; unsigned char *ptr = (unsigned char *)&sa.sin_port; UINT16_PACK(ptr, port); memcpy(&sa.sin_addr, ip, 4); return bind(s, (struct sockaddr *)&sa, sizeof(sa)); } int net_tcp4_bind_reuse(int s, unsigned char ip[4], unsigned short port) { int opt = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); return net_tcp4_bind(s, ip, port); } int net_tcp4_listen_socket(char *hostname, unsigned short port) { unsigned char ip[4]; if (!net_ip4_resolve_hostname(hostname, port, ip, NULL)) memset(ip, 0, sizeof(ip)); int sock; if (((sock = net_tcp4_nonblock_socket()) < 0) || (net_tcp4_bind_reuse(sock, ip, port) < 0) || (listen(sock, 16) < 0)) { return -1; } return sock; } int net_tcp4_accept_socket(int s, unsigned char ip[4], unsigned short *port) { struct sockaddr_in sa; int len = sizeof(sa); int fd; fd = accept(s, (struct sockaddr *)&sa, &len); if (fd == -1) return -1; memcpy(ip, (unsigned char *)&sa.sin_addr, 4); unsigned char *ptr = (unsigned char *)&sa.sin_port; *port = UINT16_UNPACK(ptr); return fd; } poc-0.4.2/http.c0000664000175000001440000002110410214014115014046 0ustar manuelusers00000000000000/* * HTTP server routines * * (c) 2005 bl0rg.net */ #include "conf.h" #include #include #include #include #include #include #include #include #include "network.h" #include "http.h" #include "misc.h" static void http_client_init(http_client_t *client); static int http_handle_client(http_server_t *server, http_client_t *client, void *data); static void http_server_assert(http_server_t *server) { assert(server != NULL); assert(server->clients != NULL); assert((server->max_clients == 0) || (server->count_clients <= server->max_clients)); assert(server->count_clients <= server->num_clients); } void http_server_reset(http_server_t *server) { assert(server != NULL); server->clients = NULL; server->num_clients = 0; server->max_clients = 0; server->callback = NULL; server->fd = -1; } int http_server_init(http_server_t *server, unsigned int num_clients, unsigned int max_clients, http_client_callback_t *callback, int fd) { assert(server != NULL); assert(num_clients > 0); assert(fd != -1); http_server_reset(server); server->clients = malloc(sizeof(http_client_t) * num_clients); if (server->clients == NULL) return 0; server->num_clients = num_clients; server->max_clients = max_clients; server->callback = callback; unsigned int i; for (i = 0; i < server->num_clients; i++) { http_client_init(server->clients + i); } server->count_clients = 0; server->fd = fd; return 1; } void http_server_close(http_server_t *server) { assert(server != NULL); if (server->clients != NULL) { unsigned int i; for (i = 0; i < server->num_clients; i++) { if (server->clients[i].fd != -1) { close(server->clients[i].fd); } } free(server->clients); } server->clients = NULL; server->num_clients = 0; server->count_clients = 0; server->max_clients = 0; if (server->fd != -1) close(server->fd); server->fd = -1; server->callback = NULL; } int http_server_realloc(http_server_t *server, unsigned int new_num_clients) { http_server_assert(server); assert(new_num_clients >= server->count_clients); http_client_t *new_clients = malloc(sizeof(http_client_t) * new_num_clients); if (new_clients == NULL) return 0; unsigned int new_count_clients = 0; unsigned int i; for (i = 0; i < server->num_clients; i++) { if (server->clients[i].fd != -1) { memcpy(new_clients + new_count_clients, server->clients + i, sizeof(http_client_t)); new_count_clients++; } } for (i = new_count_clients; i < new_num_clients; i++) http_client_init(new_clients + i); assert(new_count_clients == server->count_clients); free(server->clients); server->clients = new_clients; server->num_clients = new_num_clients; return 1; } /* * Close the connection to client with an error code. * * Sends back the error code and the comment. */ void http_bad_request(http_client_t *client, unsigned long code, const char *comment, const char *msg) { char buf[256]; int len; len = snprintf(buf, 256, "HTTP/1.0 %lu %s\r\nConnection: close\r\n\r\n%s\r\n", code, comment, msg); write(client->fd, buf, len); } /* * Accept a HTTP client connection. * * Accept the connection on the listening socket and fill the client * structure. */ int http_server_accept(http_server_t *server) { http_server_assert(server); unsigned char ip[16]; unsigned short port; int fd, i; /* Accept the connection. */ if ((fd = net_tcp4_accept_socket(server->fd, ip, &port)) < 0) return 0; if (net_tcp4_socket_nonblock(fd) == -1) { close(fd); return 0; } if ((server->max_clients == 0) || (server->count_clients < server->max_clients)) { if (server->count_clients == server->num_clients) { if (!http_server_realloc(server, server->num_clients * 2)) { fprintf(stderr, "Could not grow the size of the server structure\n"); goto exit; } } /* Find an empty client structure and fill it with filedescriptor * and timeout value */ for (i = 0; i < server->num_clients; i++) { if (server->clients[i].fd == -1) { server->clients[i].fd = fd; server->clients[i].fini = time(NULL) + HTTP_TIMEOUT; server->count_clients++; return 1; } } } exit: close(fd); return 1; } /* Check all clients for timeouts. */ void http_server_check(http_server_t *server) { http_server_assert(server); int i; for (i = 0; i < server->num_clients; i++) { if ((server->clients[i].fd != -1) && (server->clients[i].found < 2) && (time(NULL) >= server->clients[i].fini)) { http_client_close(server, server->clients); } } } /* Destroy a client structure. */ int http_client_close(http_server_t *server, http_client_t *client) { int retval = 0; if (client->fd != -1) { retval = close(client->fd); } http_client_init(client); server->count_clients--; /* trim down memory size */ if ((server->count_clients <= (server->num_clients / 4)) && (server->num_clients > HTTP_MIN_CLIENTS)) { if (!http_server_realloc(server, server->num_clients / 2)) { /* not really critical */ fprintf(stderr, "Could not cut down the size of the server structure\n"); } } http_server_assert(server); return retval; } /* Initialise a client structure. */ void http_client_init(http_client_t *client) { client->fd = -1; client->found = 0; client->in = 0; client->len = 0; } /* * Main HTTP server routine. * * Select on the listening socket and all opened client * sockets. Accept incoming connections and call the * http_client function on active clients. */ int http_server_main(http_server_t *server, void *data) { http_server_assert(server); int i; fd_set fds; struct timeval tout; tout.tv_usec = 0; tout.tv_sec = 0; FD_ZERO(&fds); /* Select the listening HTTP socket. */ FD_SET(server->fd, &fds); /* Select all active client sockets. */ for (i = 0; i < server->num_clients; i++) { if (server->clients[i].fd != -1) { FD_SET(server->clients[i].fd, &fds); } } if (select(FD_SETSIZE, &fds, NULL, NULL, &tout) < 0) { return 0; } /* Accept incoming connections. */ if (FD_ISSET(server->fd, &fds)) { if (!http_server_accept(server)) return 0; } /* Read incoming client data. */ for (i = 0; i < server->num_clients; i++) { if ((server->clients[i].fd != -1) && (FD_ISSET(server->clients[i].fd, &fds))) { if (http_handle_client(server, server->clients + i, data) < 0) { http_client_close(server, server->clients + i); } } } /* Check for client timeouts. */ http_server_check(server); return 1; } /* Read data from client connection. */ static int http_handle_client(http_server_t *server, http_client_t *client, void *data) { http_server_assert(server); time_t now; int tmp; /* Read header data. */ tmp = read(client->fd, client->buf + client->len, HTTP_MAX_HDR_LEN - client->len - 5); if (tmp <= 0) return -1; client->in += tmp; /* A header was already found. */ if (client->found >= 2) return 0; now = time(0); /* Check if the end of header is in the read data. */ for (; (client->found < 2) && (client->len < client->in); ++client->len) { if (client->buf[client->len] == '\r') continue; if (client->buf[client->len] == '\n') ++client->found; else client->found = 0; } /* The client request was too short. */ if (client->len < 10) { http_bad_request(client, 400, "Bad Request", "Not HTTP"); return -1; } client->buf[client->len] = '\0'; /* Check if the request is a ``GET /'', else discard the request. */ if (!strncasecmp(client->buf, "GET /", 5)) { if (write(client->fd, "HTTP/1.0 200 OK\r\n\r\n", 19) != 19) return -1; if (server->callback != NULL) { if (server->callback(client, data) < 0) { http_bad_request(client, 500, "Server Internal Error", "Callback returned error"); return -1; } } return 1; } else { http_bad_request(client, 400, "Bad Request", "Unsupported HTTP Method"); return -1; } return 0; } poc-0.4.2/dlist.c0000664000175000001440000002053010210123147014212 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include "dlist.h" #ifdef DMALLOC #include #endif /*M \emph{Initialize a double-linked head structure.} **/ void dlist_init(dlist_head_t *head) { assert(head != NULL); head->num = 0; head->dlist = head->end = NULL; } /*M \emph{Allocate and initialize a double-linked list node structure.} **/ dlist_t *dlist_new(void *data) { dlist_t *dlist = malloc(sizeof(dlist_t)); if (dlist) { dlist->next = NULL; dlist->prev = NULL; dlist->data = data; } return dlist; } /*M \emph{Free a double-linked list node structure.} **/ void dlist_free(dlist_t *dlist) { assert(dlist != NULL); free(dlist); } /*M \emph{Free a double-linked list node structure by calling a custom free operation on the nodes data.} **/ void dlist_delete(dlist_t *dlist, void (*free)(void *data)) { assert(dlist != NULL); if (dlist->data && free) free(dlist->data); dlist_free(dlist); } /*M \emph{Destroy a complete double-linked list.} Calls a custom delete operation on each node in the double-linked list. **/ void dlist_destroy(dlist_head_t *head, void (*free)(void *data)) { assert(head != NULL); dlist_t *dlist, *next; head->num = 0; head->end = NULL; if (!(next = head->dlist)) return; while (next) { dlist = next; next = dlist->next; dlist_delete(dlist, free); } } /*M \emph{Create a node in front of a node in a double-linked list.} Allocates a new double-linked list node structure, initializes it with data and inserts it in front of a specific node in the list. **/ dlist_t *dlist_ins_before(dlist_head_t *head, dlist_t *dlist, void *data) { assert(head != NULL); assert(dlist != NULL); dlist_t *tmp = dlist_new(data); if (!tmp) return NULL; if (dlist_insl_before(head, dlist, tmp)) { return tmp; } else { dlist_delete(tmp, NULL); return NULL; } } /*M \emph{Insert a node after a node in a double-linked list.} Inserts a node after a specific node in the double-linked list. **/ int dlist_insl_after(dlist_head_t *head, dlist_t *dlist, dlist_t *new) { assert(head != NULL); assert(dlist != NULL); assert(new != NULL); new->next = dlist->next; if (new->next) new->next->prev = new; dlist->next = new; new->prev = dlist; if (dlist == head->end) head->end = new; head->num++; return 1; } /*M \emph{Creates a node after a node in a double-linked list.} Allocates a new double-linked list node structure, initializes it with data and inserts it in front of a specific node in the list. **/ dlist_t *dlist_ins_after(dlist_head_t *head, dlist_t *dlist, void *data) { assert(head != NULL); assert(dlist != NULL); dlist_t *tmp = dlist_new(data); if (!tmp) return NULL; if (dlist_insl_after(head, dlist, tmp)) { return tmp; } else { dlist_delete(tmp, NULL); return NULL; } } /*M \emph{Insert a node before a node in a double-linked list.} Inserts a node before a specific node in the double-linked list. **/ int dlist_insl_before(dlist_head_t *head, dlist_t *dlist, dlist_t *new) { if (!head || !dlist || !new) return 0; new->prev = dlist->prev; if (new->prev) new->prev->next = new; dlist->prev = new; new->next = dlist; if (dlist == head->dlist) head->dlist = new; head->num++; return 1; } /*M \emph{Insert a node at the end of a double-linked list.} **/ int dlist_insl_end(dlist_head_t *head, dlist_t *dlist) { if (!head || !dlist) return 0; if (!head->dlist || !head->end) { head->dlist = dlist; head->end = dlist; head->num = 1; return 1; } else { return dlist_insl_after(head, head->end, dlist); } } /*M \emph{Insert a node at the front of a double-linked list.} **/ int dlist_insl_front(dlist_head_t *head, dlist_t *dlist) { if (!head || !dlist) return 0; if (!head->dlist) { head->dlist = dlist; head->end = dlist; head->num = 1; return 1; } else { return dlist_insl_before(head, head->dlist, dlist); } } /*M \emph{Creates a new node at the end of a double-linked list.} Initializes the node with data. **/ dlist_t *dlist_ins_end(dlist_head_t *head, void *data) { dlist_t *dlist = dlist_new(data); if (!dlist) return NULL; if (dlist_insl_end(head, dlist)) { return dlist; } else { dlist_delete(dlist, NULL); return NULL; } } /*M \emph{Creates a new node at the front of a double-linked list.} Initializes the node with data. **/ dlist_t *dlist_ins_front(dlist_head_t *head, void *data) { dlist_t *dlist = dlist_new(data); if (!dlist) return NULL; if (dlist_insl_front(head, dlist)) { return dlist; } else { dlist_delete(dlist, NULL); return NULL; } } /*M \emph{Pops off a specific node in a double-linked list.} **/ dlist_t *dlist_getl(dlist_head_t *head, dlist_t *dlist) { dlist_t *tmp = head->dlist; int found = 0; if (!head || !dlist || !tmp) return NULL; if (head->dlist == dlist) { head->dlist = dlist->next; if (head->dlist) head->dlist->prev = NULL; found = 1; } if (head->end == dlist) { head->end = dlist->prev; if (head->end) head->end->next = NULL; found = 1; } if (!found) { while (tmp->next && (tmp->next != dlist)) { tmp = tmp->next; } if (!tmp->next) { return NULL; } else { if ((tmp->next = dlist->next)) { tmp->next->prev = tmp; } } } head->num--; dlist->prev = dlist->next = NULL; return dlist; } /*M \emph{Pops off a specific node from a double-linked list and returns data.} Frees the popped off node. **/ void *dlist_get(dlist_head_t *head, dlist_t *dlist) { dlist_t *tmp = dlist_getl(head, dlist); void *data; if (!tmp) return NULL; else { data = tmp->data; dlist_free(tmp); return data; } } /*M \emph{Pops off the last node in a double-linked list.} **/ dlist_t *dlist_getl_end(dlist_head_t *head) { return dlist_getl(head, head->end); } /*M \emph{Pops off the front node in a double-linked list.} **/ dlist_t *dlist_getl_front(dlist_head_t *head) { return dlist_getl(head, head->dlist); } /*M \emph{Returns the data of the last node in a double-linked list.} Pops off and frees the last node. **/ void *dlist_get_end(dlist_head_t *head) { return dlist_get(head, head->end); } /*M \emph{Returns the data of the front node in a double-linked list.} Pops off and frees the front node. **/ void *dlist_get_front(dlist_head_t *head) { return dlist_get(head, head->dlist); } /*M \emph{Returns the data of the first node.} Does not pop off the first node. **/ void *dlist_front(dlist_head_t *head) { assert(head != NULL); assert(head->dlist != NULL); return head->dlist->data; } /*M \emph{Returns the data of the last node.} Does not pop off the first node. **/ void *dlist_end(dlist_head_t *head) { assert(head != NULL); assert(head->end != NULL); return head->end->data; } /*M \emph{Search a double-linked list for a matching node.} Returns the data of the node for which the dual operand operation returns TRUE. Calls the dual operand operation with the nodes data and the seed parameter data, passing the seed as first argument. **/ dlist_t *dlist_search(dlist_head_t *head, void *data, int (*cmp)(void *data, void *data2)) { dlist_t *dlist; if (!head || !head->dlist) return NULL; dlist = head->dlist; while (dlist) { if (cmp(data, dlist->data)) return dlist; dlist = dlist->next; } return NULL; } /*C **/ #ifdef DLIST_TEST #include int test_cmp(int *a, int *b) { if (*a == *b) return 1; return 0; } void test_free(int *a) { free(a); } int main(void) { dlist_head_t head; dlist_t *list; int *a[15], i; dlist_init(&head); for (i = 0; i < 15; i++) { a[i] = malloc(sizeof(int)); *a[i] = i; if (!dlist_ins_end(&head, a[i])) break; } while ((list = dlist_getl(&head, head.dlist))) dlist_delete(list, DLIST_OP(test_free)); dlist_destroy(&head, DLIST_OP(test_free)); return 1; } #endif /* DLIST_TEST */ poc-0.4.2/mp3cue.y0000664000175000001440000000620110204451551014322 0ustar manuelusers00000000000000%{ #include #include #include #include "mp3cue.h" int yylex(); extern mp3cue_file_t *yymp3_cue_file; int lc = 0; void yyerror (s) char *s; { fprintf (stderr, "Parse error on line %d: %s\n", lc, s); exit(1); } %} %token NUMBER NEWLINE STRING PERFORMER FILEID INDEX TRACK %token AUDIO COLON TITLE %token ISRC CATALOG %union { int number; char string[MP3CUE_MAX_STRING_LENGTH + 1]; } %token NUMBER %token STRING %% file: fileinformationlist tracklist | fileinformationlist tracklist fileend ; fileend: NEWLINE | NEWLINE fileend ; fileinformationlist: fileinformation NEWLINE | fileinformation NEWLINE fileinformationlist ; fileinformation: fileperformer | filetitle | fileid | filecatalog | restblubber ; filecatalog: CATALOG NUMBER ; fileperformer: PERFORMER STRING { strncpy(yymp3_cue_file->performer, $2, MP3CUE_MAX_STRING_LENGTH); } ; filetitle: TITLE STRING { strncpy(yymp3_cue_file->title, $2, MP3CUE_MAX_STRING_LENGTH); } ; fileid: FILEID STRING STRING ; restblubber: STRING { } | STRING restblubber { } ; tracklist: track tracklist | track | error { yyerrok; } ; track: trackheader NEWLINE trackinformationlist { if (++yymp3_cue_file->track_number >= yymp3_cue_file->max_track_number) { int tracks = yymp3_cue_file->max_track_number * 2; mp3cue_track_t *oldtracks = yymp3_cue_file->tracks; if (!(yymp3_cue_file->tracks = realloc(yymp3_cue_file->tracks, tracks * sizeof(mp3cue_track_t)))) { fprintf(stderr, "Could not allocate memory for more tracks!\n"); // XXX error yymp3_cue_file->tracks = oldtracks; } else { yymp3_cue_file->max_track_number = tracks; } } } ; trackinformationlist: trackinformation NEWLINE | trackinformation NEWLINE trackinformationlist ; trackinformation: tracktitle | trackperformer | trackindex | trackisrc | restblubber //| error { yyerrok; } ; trackheader: TRACK NUMBER AUDIO { yymp3_cue_file->tracks[yymp3_cue_file->track_number].number = $2; yymp3_cue_file->tracks[yymp3_cue_file->track_number].type = mp3cue_audio; yymp3_cue_file->tracks[yymp3_cue_file->track_number].title[0] = '\0'; yymp3_cue_file->tracks[yymp3_cue_file->track_number].performer[0] = '\0'; yymp3_cue_file->tracks[yymp3_cue_file->track_number].index.minutes = 0; yymp3_cue_file->tracks[yymp3_cue_file->track_number].index.seconds = 0; yymp3_cue_file->tracks[yymp3_cue_file->track_number].index.centiseconds = 0; } ; trackisrc: ISRC STRING ; tracktitle: TITLE STRING { strncpy(yymp3_cue_file->tracks[yymp3_cue_file->track_number].title, $2, MP3CUE_MAX_STRING_LENGTH); } ; trackperformer: PERFORMER STRING { strncpy(yymp3_cue_file->tracks[yymp3_cue_file->track_number].performer, $2, MP3CUE_MAX_STRING_LENGTH); } ; trackindex: INDEX NUMBER NUMBER COLON NUMBER COLON NUMBER { if ($2 == 1) { if (yymp3_cue_file->track_number > 0) { yymp3_cue_file->tracks[yymp3_cue_file->track_number-1].index.minutes = $3; yymp3_cue_file->tracks[yymp3_cue_file->track_number-1].index.seconds = $5; yymp3_cue_file->tracks[yymp3_cue_file->track_number-1].index.centiseconds = $7; } } } ; %% poc-0.4.2/crc32.h0000664000175000001440000000065710210123147014024 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef CRC32_H__ #define CRC32_H__ typedef struct crc32_s { unsigned long poly; unsigned long init; unsigned long xor; unsigned long table[256]; } crc32_t; void crc32_init(crc32_t *crc, unsigned long poly, unsigned long init, unsigned long xor); unsigned long crc32(crc32_t *crc, unsigned char *data, unsigned long len); #endif /* CRC32_H__ */ /*C **/ poc-0.4.2/id3.h0000664000175000001440000000215410202701632013563 0ustar manuelusers00000000000000/* * id3v2 generation routines * * v2 only because this seems to be supported by most players * * (c) 2005 bl0rg.net */ #ifndef ID3_H__ #define ID3_H__ #define ID3_TAG_SIZE 8192 #define ID3_HEADER_SIZE 10 #include "file.h" unsigned int id3_fill_comment(unsigned char *buf, unsigned int len, unsigned char encoding, unsigned char *short_comment, unsigned char *long_comment, unsigned char *language); unsigned int id3_fill_tframe(unsigned char *buf, unsigned int len, unsigned char *type, unsigned char encoding, unsigned char *string); int id3_fill_header(unsigned char *buf, unsigned int len, unsigned long id3_size); int id3_write_tag(file_t *outfile, unsigned char *album_title, unsigned char *artist, unsigned char *title, unsigned int track_number, unsigned char *comment); #endif /* ID3_H__ */ poc-0.4.2/man/0000775000175000001440000000000010230546555013520 5ustar manuelusers00000000000000poc-0.4.2/man/man1/0000775000175000001440000000000010230546555014354 5ustar manuelusers00000000000000poc-0.4.2/man/man1/mp3length.10000664000175000001440000000072710203362301016326 0ustar manuelusers00000000000000.TH MP3LENGTH 1 "February 2005" "" "User Command" .SH NAME .B mp3length \- show the length of a MP3 file .SH SYNOPSIS .B mp3length .I mp3file .br .SH DESCRIPTION .B mp3length prints the length of a MP3 file in a human readable format. The length is calculated by counting the ADUs in the MP3 file. The primary goal of this program was to assist development of .B mp3cue and .B mp3cut. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/pob-2250.10000664000175000001440000000201710203362301015565 0ustar manuelusers00000000000000.TH POB\-2250 1 "February 2005" "" "User Command" .SH NAME .B pob\-2250 \- receive RTP RFC 2250 MP3 streams .SH SYNOPSIS .B pob\-2250 .RB [ .I \-s address .RB ] .RB [ .I \-p port .RB ] .RB [ .I \-b size .RB ] .RB [ .I \-q .RB ] .SH DESCRIPTION .B pob\-2250 receives a RTP MP3 Stream using the protocol described in RFC 2250. The incoming stream is buffered and written to standard out in order to be fed into a MP3 decoder. .SH OPTIONS .IP "-s address" Specify the address to listen to (default 224.0.1.23). If the address is a multicast address, group membership is requested automatically. .IP "-p port" Specify the port to listen to. .IP "-b size" Specify the maximal number of packet that are hold in the ring buffer (default 128). .IP "-q" Don't output any information on standard error. .SH EXAMPLES .IP "pob-2250 -s 224.0.1.24 -p 8989 | mpg123 -" Receive the MP3 RTP stream sent to 224.0.1.24 on port 8989 and feed it into the MP3 decoder mpg123. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/poc-2250.10000664000175000001440000000204310203363321015570 0ustar manuelusers00000000000000.TH POC\-2250 1 "February 2005" "" "User Command" .SH NAME .B poc\-2250 \- send RTP RFC 2250 MP3 streams .SH SYNOPSIS .B poc\-2250 .RB [ .I \-s address .RB ] .RB [ .I \-p port .RB ] .RB [ .I \-t ttl .RB ] .RB [ .I \-q .RB ] .I files... .SH DESCRIPTION .B poc\-2250 is a streaming server sending mp3 data using the RTP RFC 2250 protocol. It sends the .I files in the order given on the command-line. Use the filename .I \- to stream from standard input. Normally, RTP is used to stream to multicast groups. .SH OPTIONS .IP "-s address" Specify the address to send to (default 224.0.1.23). .IP "-p port" Specify the port to send to (default 1500). .IP "-t ttl" Specify the TTL parameter to be set on outgoing parameters (default 1). .IP "-q" Don't output any information on standard error. .SH EXAMPLES .IP "poc-2250 -s 224.0.1.24 -p 8989 -t 2 bla.mp3" Send the file .I bla.mp3 using the RTP RFC 2250 protocol to the address 224.0.1.24 on port 8989, and set the TTL to 2. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/pogg-http.10000664000175000001440000000202010203363321016325 0ustar manuelusers00000000000000.TH POGG\-HTTP 1 "February 2005" "" "User Command" .SH NAME .B pogg\-http \- send HTTP OGG streams .SH SYNOPSIS .B pogg\-http .RB [ .I \-s address .RB ] .RB [ .I \-p port .RB ] .RB [ .I \-t ttl .RB ] .RB [ .I \-q .RB ] .RB [ .I \-k http_k .RB ] .RB [ .I \-n http_n .RB ] .I files... .SH DESCRIPTION .B pogg\-http is a streaming server sending ogg data using the HTTP protocol. It sends the .I files in the order given on the command-line. Use the filename .I \- to stream from standard input. .SH OPTIONS .IP "-s address" Specify the address to listen to (default 0.0.0.0). .IP "-p port" Specify the port to listen to (default 8000). .IP "-q" Don't output any information on standard error. .IP "-c clients" Specify the maximal number of clients (default 16). .SH EXAMPLES .IP "pogg-http -p 8989 -c 32 bla.ogg" Send the file .I bla.ogg using the HTTP protocol, accepting connections on the port 8989. The server will accept a maximum of 32 connections. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/pob-fec.10000664000175000001440000000242710203362301015737 0ustar manuelusers00000000000000.TH POB\-FEC 1 "February 2005" "" "User Command" .SH NAME .B pob\-fec \- receive FEC MP3 streams .SH SYNOPSIS .B pob\-fec .RB [ .I \-s address .RB ] .RB [ .I \-p port .RB ] .RB [ .I \-b size .RB ] .RB [ .I \-q .RB ] .SH DESCRIPTION .B pob\-fec receives a FEC MP3 stream using a custom protocol. The streamed MP3 frames are first decomposed in autonomous data units (ADUs). These ADUs are grouped into ADU groups, which are encoded redundantly using a FEC method by Luigi Rizzo. For example, a group if 8 ADUs can be encoded into 16 packets. Any 8 received packets of these 16 packets is sufficient to recover the original 8 ADUs. The incoming MP3 stream is decoded, buffered and written to stdout. .SH OPTIONS .IP "-s address" Specify the address to listen to (default 224.0.1.23). If the address is a multicast address, group membership is requested automatically. .IP "-p port" Specify the port to listen to. .IP "-b size" Specify the number of ADU groups that are hold in the buffer (default 16). .IP "-q" Don't output any information on standard error. .SH EXAMPLES .IP "pob-fec -s 224.0.1.24 -p 8989 | mpg123 -" Receive the MP3 FEC stream sent to 224.0.1.24 on port 8989 and feed it into the MP3 decoder mpg123. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/mp3cut.10000664000175000001440000000360510203140663015643 0ustar manuelusers00000000000000.TH MP3CUT 1 "February 2005" "" "User Command" .SH NAME .B mp3cut \- cut and assemble MP3 files .SH SYNOPSIS .B mp3cut .RB [ .I \-o outputfile .RB ] .RB [ .I \-T title .RB ] .RB [ .I \-A artist .RB ] .RB [ .I \-N album\-name .RB ] .RB [ .I -t [hh:]mm:ss[+ms]-[hh:]mm:ss[+ms] .RB ] .I mp3file .RB [ [ .I -t ... .RB ] .I mp3file1 .RB ... ] .br .SH DESCRIPTION The .B mp3cut utility cuts and assembles MP3 files according to the time specifications given on the command line. The mp3 output is written to the outputfile. If no .B outputfile is given on the command\-line, the name for the outputfile is created from the name of the first mp3 file by adding .B output.mp3 at the end. The .B \-t flag specifies which part of the mp3 file following it will be extracted. .SH OPTIONS .IP "-o outputfile" Specify where the output is to be written. .IP "-T title" Specify the title ID3 tag for the output file. .IP "-A artist" Specify the artist ID3 tag for the output file. .IP "-N album\-name" Specify the album name ID3 tag for the output file. .IP "-t [hh:]mm:ss[+ms]-[hh:]mm:ss[+ms]" Specify which part of the following mp3file will be included in the output file. hh = hours mm = minutes ss = seconds ms = milliseconds If the starting time is omitted, .B 00:00:00+00 is used as starting time. If the ending time is omitted, the end of the MP3 file is used as ending time. .SH EXAMPLES .IP "mp3cut -o output.mp3 -t 23:42+500-01:23:42+750 input.mp3" Cut the segment from 23 minutes, 42 seconds and 500 milliseconds to 1 hour, 23 minutes, 42 seconds and 750 milliseconds from input.mp3 and write the output to output.mp3. .IP "mp3cut -t 00:01-00:02 input1.mp3 -t -15:23 input2.mp3 -t 9:87+500- input3.mp3" Append the segments from input1.mp3, input2.mpt and input3.mp3 and write the output to input1.output.mp3. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/pob-3119.10000664000175000001440000000201710203362301015572 0ustar manuelusers00000000000000.TH POB\-3119 1 "February 2005" "" "User Command" .SH NAME .B pob\-3119 \- receive RTP RFC 3119 MP3 streams .SH SYNOPSIS .B pob\-3119 .RB [ .I \-s address .RB ] .RB [ .I \-p port .RB ] .RB [ .I \-b size .RB ] .RB [ .I \-q .RB ] .SH DESCRIPTION .B pob\-3119 receives a RTP MP3 Stream using the protocol described in RFC 3119. The incoming stream is buffered and written to standard out in order to be fed into a MP3 decoder. .SH OPTIONS .IP "-s address" Specify the address to listen to (default 224.0.1.23). If the address is a multicast address, group membership is requested automatically. .IP "-p port" Specify the port to listen to. .IP "-b size" Specify the maximal number of packet that are hold in the ring buffer (default 128). .IP "-q" Don't output any information on standard error. .SH EXAMPLES .IP "pob-3119 -s 224.0.1.24 -p 8989 | mpg123 -" Receive the MP3 RTP stream sent to 224.0.1.24 on port 8989 and feed it into the MP3 decoder mpg123. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/mp3cue.10000664000175000001440000000140210203362301015610 0ustar manuelusers00000000000000.TH MP3CUE 1 "February 2005" "" "User Command" .SH NAME .B mp3cue \- cut a MP3 file according to a CUE file .SH SYNOPSIS .B mp3cue .RB -c .I cuefile .I mp3file .br .SH DESCRIPTION The .B mp3cue utility cuts a MP3 file .B mp3file containing multiple tracks according to a CUE file .B cuefile. The length and position of the single tracks is read from the CUE file, and new tracks are created accordingly. The tracks are named according to the artist and album information contained in the CUE file, and ID3 v2 tags are set accordingly. The MP3 file is not cut on frame boundary, but on ADU (autonomous data unit) boundary, thus avoiding glitches and cracks in the resulting MP3 files. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/poc-3119.10000664000175000001440000000204410203363321015576 0ustar manuelusers00000000000000.TH POC\-3119 1 "February 2005" "" "User Command" .SH NAME .B poc\-3119 \- send RTP RFC 3119 MP3 streams .SH SYNOPSIS .B poc\-3119 .RB [ .I \-s address .RB ] .RB [ .I \-p port .RB ] .RB [ .I \-t ttl .RB ] .RB [ .I \-q .RB ] .I files... .SH DESCRIPTION .B poc\-3119 is a streaming server sending mp3 data using the RTP RFC 3119 protocol. It sends the .I files in the order given on the command-line. Use the filename .I \- to stream from standard input. Normally, RTP is used to stream to multicast groups. .SH OPTIONS .IP "-s address" Specify the address to send to (default 224.0.1.23). .IP "-p port" Specify the port to send to (default 1500). .IP "-t ttl" Specify the TTL parameter to be set on outgoing parameters (default 1). .IP "-q" Don't output any information on standard error. .SH EXAMPLES .IP "poc-3119 -s 224.0.1.24 -p 8989 -t 2 bla.mp3" Send the file .I bla.mp3 using the RTP RFC 3119 protocol to the address 224.0.1.24 on port 8989, and set the TTL to 2. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/poc-fec.10000664000175000001440000000353610203363321015745 0ustar manuelusers00000000000000.TH POC\-FEC 1 "February 2005" "" "User Command" .SH NAME .B poc\-fec \- send FEC MP3 streams .SH SYNOPSIS .B poc\-fec .RB [ .I \-s address .RB ] .RB [ .I \-p port .RB ] .RB [ .I \-t ttl .RB ] .RB [ .I \-q .RB ] .RB [ .I \-k fec_k .RB ] .RB [ .I \-n fec_n .RB ] .I files... .SH DESCRIPTION .B poc\-fec is a streaming server sending mp3 data using a custom FEC protocol. The streamed MP3 frames are first decomposed in autonomous data units (ADUs). These ADUs are grouped into ADU groups, which are encoded redundantly using a FEC method by Luigi Rizzo. A group of k ADUs is encoded as n data packets. Any k of these n data packets is sufficient to recover the original k ADUs. It sends the .I files in the order given on the command-line. Use the filename .I \- to stream from standard input. Normally, the FEC protocol is used to stream to multicast groups. .SH OPTIONS .IP "-s address" Specify the address to send to (default 224.0.1.23). .IP "-p port" Specify the port to send to (default 1500). .IP "-t ttl" Specify the TTL parameter to be set on outgoing parameters (default 1). .IP "-q" Don't output any information on standard error. .IP "-k fec_k" Specify the number of ADUs that will be encoded as an ADU group (default 20). .IP "-n fec_n" Specify the number of packets that the ADU groups will be encoded to (default 25). This number must be greater than the fec_k parameter. .SH EXAMPLES .IP "poc-fec -s 224.0.1.24 -p 8989 -t 2 -k 16 -n 32 bla.mp3" Send the file .I bla.mp3 using the RTP RFC fec protocol to the address 224.0.1.24 on port 8989, and set the TTL to 2. MP3 frames of bla.mp3 are converted to ADUs and grouped in ADU groups of 16 ADUs. These 16 ADUs are encoded into 32 packets and streamed. A client will have to receive at least 16 packets to recover the original ADUs. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/man/man1/poc-http.10000664000175000001440000000201710203363321016160 0ustar manuelusers00000000000000.TH POC\-HTTP 1 "February 2005" "" "User Command" .SH NAME .B poc\-http \- send HTTP MP3 streams .SH SYNOPSIS .B poc\-http .RB [ .I \-s address .RB ] .RB [ .I \-p port .RB ] .RB [ .I \-t ttl .RB ] .RB [ .I \-q .RB ] .RB [ .I \-k http_k .RB ] .RB [ .I \-n http_n .RB ] .I files... .SH DESCRIPTION .B poc\-http is a streaming server sending mp3 data using the HTTP protocol. It sends the .I files in the order given on the command-line. Use the filename .I \- to stream from standard input. .SH OPTIONS .IP "-s address" Specify the address to listen to (default 0.0.0.0). .IP "-p port" Specify the port to listen to (default 8000). .IP "-q" Don't output any information on standard error. .IP "-c clients" Specify the maximal number of clients (default 16). .SH EXAMPLES .IP "poc-http -p 8989 -c 32 bla.mp3" Send the file .I bla.mp3 using the HTTP protocol, accepting connections on the port 8989. The server will accept a maximum of 32 connections. .SH AUTHORS Manuel Odendahl , Florian Wesch poc-0.4.2/aq.c0000664000175000001440000004705010210123147013502 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #ifdef DMALLOC #include #endif #ifdef DEBUG #include #endif #include #include "aq.h" static void aq_discard_top_frame(aq_t *q); static void aq_discard_top_adu(aq_t *q); static void aq_enqueue_frame(aq_t *q, mp3_frame_t *frame); static void aq_enqueue_adu(aq_t *q, adu_t *adu); static void aq_make_adu(aq_t *q); static void aq_insert_dummy_adu(aq_t *q, unsigned int backptr); static void aq_insert_dummy_adus(aq_t *q); static int aq_need_adu(aq_t *q); static void aq_make_frame(aq_t *q); /*S General ADU queue functions **/ /*M \emph{Initialize an ADU queue structure.} **/ void aq_init(aq_t *q) { assert(q != NULL); dlist_init(&q->frames); dlist_init(&q->adus); q->size = 0; } /*M \emph{Destroy an ADU queue structure.} **/ void aq_destroy(aq_t *q) { assert(q != NULL); dlist_destroy(&q->frames, free); dlist_destroy(&q->adus, free); } /*M \emph{Enqueue a new frame into the ADU queue.} \verb|malloc| a new MP3 frame structure and initialize it by copying the content of \verb|frame|. Append the new MP3 frame structure to the frames linked list of the ADU queue. Add the size of \verb|frame|'s audio data ($\verb|frame size| - \verb|sideinfo size| - \verb|header size|$) to the total queue size. **/ static void aq_enqueue_frame(aq_t *q, mp3_frame_t *frame) { assert(q != NULL); assert(frame != NULL); mp3_frame_t *tmp_frame = malloc(sizeof(mp3_frame_t)); assert(tmp_frame != NULL); memcpy(tmp_frame, frame, sizeof(mp3_frame_t)); dlist_t *dlist = dlist_ins_end(&q->frames, tmp_frame); assert(dlist != NULL); q->size += tmp_frame->frame_data_size; } /*M \emph{Enqueue a new ADU into the ADU queue.} **/ static void aq_enqueue_adu(aq_t *q, adu_t *adu) { assert(q != NULL); assert(adu != NULL); adu_t *tmp_adu = malloc(sizeof(adu_t)); assert(tmp_adu != NULL); memcpy(tmp_adu, adu, sizeof(adu_t)); dlist_t *dlist = dlist_ins_end(&q->adus, tmp_adu); assert(dlist != NULL); } /*M \emph{Returns the tail MPEG Frame in the queue.} **/ dlist_t *aq_tail_frame(aq_t *q) { assert(q != NULL); return q->frames.end; } /*M \emph{Returns the top MPEG Frame in the queue.} **/ dlist_t *aq_top_frame(aq_t *q) { assert(q != NULL); return q->frames.dlist; } /*M \emph{Returns the tail ADU in the queue.} **/ dlist_t *aq_tail_adu(aq_t *q) { assert(q != NULL); return q->adus.end; } /*M \emph{Returns the top ADU in the queue.} **/ dlist_t *aq_top_adu(aq_t *q) { assert(q != NULL); return q->adus.dlist; } /*M \emph{Pops the front ADU off the queue.} **/ adu_t *aq_get_adu(aq_t *q) { return dlist_get_front(&q->adus); } /*M \emph{Pops the front MPEG Frame off the queue.} Recalculates the total frame data size of the queue. **/ mp3_frame_t *aq_get_frame(aq_t *q) { mp3_frame_t *res = dlist_get_front(&q->frames); if (res) q->size -= res->frame_data_size; return res; } /*M \emph{Discard the top MPEG Frame of the queue.} Recalculates the total frame data size of the queue. **/ static void aq_discard_top_frame(aq_t *q) { assert(q->frames.dlist != NULL); mp3_frame_t *frame = dlist_get(&q->frames, q->frames.dlist); assert(frame != NULL); q->size -= frame->frame_data_size; free(frame); } /*M \emph{Discard the top ADU of the queue.} **/ static void aq_discard_top_adu(aq_t *q) { assert(q->adus.dlist != NULL); adu_t *adu = dlist_get(&q->adus, q->adus.dlist); assert(adu != NULL); free(adu); } /*M \emph{Generate an ADU frame out of MPEG frames.} Enqueue frames into the queue until there is enough data to generate the ADU for the most recently enqueued frame. \begin{algorithm} \item[A1:] [Enqueue a new frame] \verb|size_before| $\leftarrow$ size of the queue before enqueuing, enqueue the new MP3 frame and add the frame size of the new MP3 frame to the size of queue. \verb|size_after| $\leftarrow$ size of queue after enqueuing. \item[A2:] [Check if new frame can be used to generate an ADU] If the backpointer of the new frame is bigger than \verb|size_before| then goto {\bf A1}. \item[A3:] [Check for enough data] [ If the size of the queue is smaller than the adu size of the new frame then goto {\bf A1}. \end{algorithm} Now an ADU can be generated for the newest frame. The older frames cannot be transformed to ADUs as data is missing. Get the first frame in the queue containing ADU data for this frame, and get the offset into the frame data. \begin{algorithm} \item[B1:] [Initialize] \verb|prev_bytes| $\leftarrow$ backpointer of newest frame. \item[B2:] [Handle previous frame] \verb|a| $\leftarrow$ the previous enqueued frame. Substract the frame size of \verb|a| from \verb|prev_bytes|. \item[B3:] [Check for enough data] If \verb|prev_bytes| $\leq$ 0 then \verb|offset| $\leftarrow$ $-$ \verb|prev_bytes| and stop, else goto {\bf B2}. \end{algorithm} Now \verb|a| is the first frame containing data for the ADU, and \verb|offset| contains the offset into the frame data of \verb|a|. All olders frames can be discarded. \begin{algorithm} \item[C1:] If queue head $\leftarrow$ \verb|a| then stop, else free the queue head and goto {\bf C1}. \end{algorithm} Get the ADU data. \begin{algorithm} \item[D1:] [Initialize] \verb|adu_size| $\leftarrow$ \verb|adu_size| of newest frame. \item[D2:] [Copy data from frame into ADU] A: \verb|data_here| $\leftarrow$ frame size of \verb|a| $-$ \verb|offset|, \verb|bytes_here| $\leftarrow$ minimum of \verb|data_here| and \verb|adu_size|, get \verb|bytes_here| bytes of data from current frame at offset \verb|offset|, substract \verb|bytes_here| from \verb|adu_size|. \item[D3:] [Get next frame] \verb|a| $\leftarrow$ next frame in queue, \verb|offset| $\leftarrow$ 0. If \verb|adu_size| $>$ 0 then goto {\bf D2}, else stop. \end{algorithm} **/ static void aq_make_adu(aq_t *q) { /* get tail frame */ dlist_t *dlist = aq_tail_frame(q); assert(dlist != NULL); mp3_frame_t *tail = dlist->data; assert(tail != NULL); unsigned int back_ptr = tail->si.main_data_end; adu_t adu; memcpy(&adu, tail, sizeof(adu_t)); /* get first frame containing ADU data */ int offset = 0; while (back_ptr > 0) { dlist = dlist->prev; assert(dlist != NULL); mp3_frame_t *prev_frame = dlist->data; assert(prev_frame != NULL); if (prev_frame->frame_data_size < back_ptr) { back_ptr -= prev_frame->frame_data_size; } else { offset = prev_frame->frame_data_size - back_ptr; break; } } /* discard unneeded top frames */ while (aq_top_frame(q) != dlist) aq_discard_top_frame(q); /* fill adu data */ int adu_size = tail->adu_size; unsigned char *adu_ptr = mp3_frame_data_begin(&adu); while (adu_size > 0) { assert(dlist != NULL); mp3_frame_t *f = dlist->data; assert(f != NULL); int data_here = f->frame_data_size - offset; int bytes_here = adu_size > data_here ? data_here : adu_size; unsigned char *ptr = mp3_frame_data_begin(f); assert(((bytes_here + offset) <= (long)f->frame_data_size) || "Frame is too short"); memcpy(adu_ptr, ptr + offset, bytes_here); adu_ptr += bytes_here; adu_size -= bytes_here; dlist = dlist->next; offset = 0; } aq_enqueue_adu(q, &adu); } /*M \emph{Add a MPEG frame to the queue and generate an ADU if possible.} Returns 0 if no ADU could be generated, 1 if an ADU could be generated. **/ int aq_add_frame(aq_t *q, mp3_frame_t *frame) { assert(q != NULL); assert(frame != NULL); int back_ptr = frame->si.main_data_end; int size_before = q->size; /* discard broken frames */ if (frame->adu_size > (frame->frame_data_size + back_ptr)) { fprintf(stderr, "Broken frame, skipping...\n"); return 0; } assert(frame->adu_size <= (frame->frame_data_size + back_ptr)); aq_enqueue_frame(q, frame); if ((size_before < back_ptr) || (q->size < frame->adu_size)) return 0; aq_make_adu(q); return 1; } /*M \emph{Algorithms to convert ADU frames back to MP3 frames.} Enqueue ADU frames into the queue until there is enough data to generate the MP3 for the head ADU. \begin{algorithm} \item[A1:] [Initialize] \verb|frame_len| $\leftarrow$ \verb|frame_data_size| of head ADU, \verb|previous_frame_size| $\leftarrow$ 0, \verb|adu| $\leftarrow$ head ADU. \item[A2:] A: \verb|data_end| $\leftarrow$ size of \verb|adu| $-$ backpointer of \verb|adu| $+$ \verb|previous_frame_size|. \item[A3:] [Check for enough data] If \verb|data_end| $>$ \verb|frame_len| then stop, else add the \verb|frame_data_size| of \verb|adu| to \verb|previous_frame_size|. \item[A4:] [Check for more ADUs] If there are no more ADUs in the queue stop (more ADUs are needed), else \verb|adu| $\leftarrow$ next ADU and goto {\bf A2}. \end{algorithm} After an ADU frame is enqueued, check if there are missing ADUs (the backpointer of the recently enqueued ADU overlaps the data of the previous ADU). \begin{algorithm} \item[B1:] [Initialize] \verb|adu| $\leftarrow$ tail ADU of the ADU queue. \item[B2:] [Get previous ADU] If there is no previous ADU, \verb|prev_adu_end| $\leftarrow$ 0 and goto {\bf B4}, else \verb|prev_adu| $\leftarrow$ previous ADU, \verb|prev_adu_end| $\leftarrow$ \verb|frame_data_size| of \verb|prev_adu| $+$ \verb|main_data_end| of \verb|prev_adu| $-$ \verb|adu_size| of \verb|prev_adu|. \item[B3:] [Check previous ADU] If \verb|prev_adu_end| $<$ 0 the frame was not well formed, abort. \item[B4:] [Check if an ADU is missing] If the \verb|main_data_end| of \verb|adu| $>$ \verb|prev_adu_end| an ADU is missing, insert a dummy ADU in front of the tail and goto {\bf B2}. \end{algorithm} If there are enough ADUs in the queue, generate the top frame. \begin{algorithm} \item[C1:] [Initialize the new MPEG frame] Copy the header and sideinfo from top adu into mp3 frame, zero out the frame data. \item[C2:] [Initialize] \verb|adu| $\leftarrow$ top adu, offset of data in previous adus $\leftarrow$ 0. \item [C3:] [Calculate beginning of data] A: \verb|data_start| (beginning of data contained in adu relative to beginning of the mp3 frame data) $\leftarrow$ offset of data in previous adus $-$ \verb|main_data_end| of \verb|adu|. \item[C4:] [] If \verb|data_start| $>$ \verb|frame_data_size| of mp3 frame then goto B, else \verb|data_end| (end of data contained in \verb|adu| relative to begging of the mp3 frame data) $\leftarrow$ maximum of (\verb|data_start| $+$ size of \verb|adu|) and \verb|frame_data_size| of mp3 frame. \item[C5:] [Calculate data offsets] If \verb|data_start| $<$ 0 then \verb|from_offset| $\leftarrow$ $-$ \verb|data_start|, \verb|to_offset| $\leftarrow$ 0 and \verb|data_length| $\leftarrow$ \verb|data_end| else \verb|from_offset| $\leftarrow$ 0, \verb|to_offset| $\leftarrow$ \verb|data_start| and \verb|data_length| $\leftarrow$ \verb|data_end| $-$ \verb|data_start|. \item[C6:] [Copy data from ADU to frame] Copy \verb|data_length| from \verb|adu| at offset \verb|from_offset| to mp3 frame at offset \verb|to_offset| and add \verb|frame_data_size| of \verb|adu| to offset of data in previous adus. \item[C7:] If \verb|data_end| $<$ \verb|frame_data_size| of mp3 frame then \verb|adu| $\leftarrow$ next adu in queue and goto A. \item[C8:] B: Discard top ADU. \end{algorithm} **/ /*M \emph{Insert a dummy ADU.} Inserts a dummy ADU by copying the frame header and sideinfo information of tail ADU and zeroing out \verb|main_data_end| and the length fields. **/ static void aq_insert_dummy_adu(aq_t *q, unsigned int backptr) { assert(q != NULL); #ifdef DEBUG fprintf(stderr, "XXX insert dummy adu backptr %d\n", backptr); #endif dlist_t *dlist = aq_tail_adu(q); assert(dlist != NULL); adu_t *tail = dlist->data; assert(tail != NULL); adu_t *dummy = malloc(sizeof(adu_t)); assert(dummy != NULL); /* structure copy */ *dummy = *tail; /* zero out backpointer and sideinfo length information */ dummy->si.main_data_end = backptr; unsigned int i, j; for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) { dummy->si.channel[i].granule[j].part2_3_length = dummy->si.channel[i].granule[j].big_values = 0; dummy->si.channel[i].granule[j].scale_comp = 0; dummy->si.channel[i].granule[j].tbl_sel[0] = dummy->si.channel[i].granule[j].tbl_sel[1] = dummy->si.channel[i].granule[j].tbl_sel[2] = 0; } dummy->adu_size = dummy->adu_bitsize = 0; dlist_t *new = dlist_ins_before(&q->adus, dlist, dummy); assert(new != NULL); } /*M \emph{Insert dummy ADUs if necessary.} **/ static void aq_insert_dummy_adus(aq_t *q) { assert(q != NULL); dlist_t *dlist = aq_tail_adu(q); assert(dlist != NULL); adu_t *tail = dlist->data; assert(tail != NULL); unsigned int prev_adu_end = 0; if (dlist->prev) { adu_t *prev = dlist->prev->data; assert(prev != NULL); prev_adu_end = prev->frame_data_size + prev->si.main_data_end - prev->adu_size; assert((prev_adu_end >= 0) || "bad formed ADU frame"); } /* insert the necessary dummy adus */ int back_ptr = tail->si.main_data_end - prev_adu_end; for (; back_ptr > 0; back_ptr -= tail->frame_data_size, prev_adu_end = 0) aq_insert_dummy_adu(q, prev_adu_end); } //#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) minbla(a, b) long minbla(long a, long b) { return (a < b ? a : b); } /*M \emph{Make a MP3 frame from ADUs.} **/ static void aq_make_frame(aq_t *q) { assert(q != NULL); dlist_t *dlist = aq_top_adu(q); assert(dlist != NULL); adu_t *top = dlist->data; assert(top != NULL); #ifdef DEBUG fprintf(stderr, "top adu size: %d, frame size: %d\n", top->adu_size, top->frame_data_size); #endif mp3_frame_t frame; memcpy(&frame, top, sizeof(adu_t)); memset(frame.raw, 0, MP3_RAW_SIZE); unsigned int frames_offset = 0; int data_end = 0; do { assert (dlist != NULL); adu_t *adu = dlist->data; assert(adu != NULL); #ifdef DEBUG fprintf(stderr, "frames offset %d, backptr %d\n", frames_offset, adu->si.main_data_end); #endif int data_start = frames_offset - adu->si.main_data_end; if (data_start > (long)frame.frame_data_size) break; assert(data_start <= (long)frame.frame_data_size); data_end = MIN(data_start + adu->adu_size, (long)frame.frame_data_size); #ifdef DEBUG fprintf(stderr, "data_start: %d, data_end: %d\n", data_start, data_end); #endif unsigned int from_offset, to_offset, data_length; if (data_start < 0) { from_offset = -data_start; to_offset = 0; if (data_end < 0) data_length = 0; else data_length = data_end; } else { from_offset = 0; to_offset = data_start; data_length = data_end - data_start; } if (data_length > 0) { assert(adu->adu_size >= from_offset + data_length); #ifdef DEBUG fprintf(stderr, "memcpy (size: %d) from [%d:%d] to [%d:%d]\n", adu->adu_size, from_offset, from_offset + data_length, to_offset, to_offset + data_length); #endif memcpy(mp3_frame_data_begin(&frame) + to_offset, mp3_frame_data_begin(adu) + from_offset, data_length); } frames_offset += adu->frame_data_size; dlist = dlist->next; } while (data_end < (long)frame.frame_data_size); aq_discard_top_adu(q); aq_enqueue_frame(q, &frame); } /*M \emph{Check if there are enough ADUs in the queue to generate a new MPEG frame.} **/ static int aq_need_adu(aq_t *q) { assert(q != NULL); dlist_t *dlist = aq_top_adu(q); assert(dlist != NULL); adu_t *head = dlist->data; assert(head != NULL); int frame_len = head->frame_data_size; #ifdef DEBUG fprintf(stderr, "aq_need_adu: frame_len: %u\n", frame_len); #endif int prev_frames_size = 0; while (dlist) { adu_t *adu = dlist->data; assert(adu != NULL); int data_end = prev_frames_size + adu->adu_size - adu->si.main_data_end; #ifdef DEBUG fprintf(stderr, "aq_need_adu: data_end: %d, prev_frames_size %u, adu_size %u, main_data_end %u\n", data_end, prev_frames_size, adu->adu_size, adu->si.main_data_end); #endif if (data_end >= frame_len) return 1; prev_frames_size += adu->frame_data_size; dlist = dlist->next; } return 0; } /*M \emph{Adds an ADU to the queue and generates a MPEG frame if possible.} **/ int aq_add_adu(aq_t *q, adu_t *adu) { assert(q != NULL); assert(adu != NULL); aq_enqueue_adu(q, adu); aq_insert_dummy_adus(q); if (aq_need_adu(q)) { aq_make_frame(q); return 1; } else { return 0; } } /*C **/ #ifdef AQ1_TEST #include int main(int argc, char *argv[]) { mp3_file_t file; mp3_frame_t frame; aq_t qin; char *f; if (!(f = *++argv)) { fprintf(stderr, "Usage: aq1 mp3file\n"); return 1; } aq_init(&qin); if (!mp3_open_read(&file, f)) { fprintf(stderr, "Could not open mp3 file: %s\n", f); return 1; } while (mp3_next_frame(&file, &frame) > 0) { if (!aq_add_frame(&qin, &frame)) { printf("could not generate an ADU\n"); } else { printf("could generate an ADU\n"); } fgetc(stdin); } file_close(&file); aq_destroy(&qin); return 0; } #endif /* AQ1_TEST */ #ifdef AQ2_TEST #include unsigned long cksum(unsigned char *buf, int cnt) { unsigned long res = 0; int i; for (i = 0; i < cnt; i++) res += buf[i]; return res; } int main(int argc, char *argv[]) { char *f[2]; if (!(f[0] = *++argv) || !(f[1] = *++argv)) { fprintf(stderr, "Usage: mp3-write mp3in mp3out\n"); return 1; } file_t in; if (!file_open_read(&in, f[0])) { fprintf(stderr, "Could not open mp3 file for read: %s\n", f[0]); return 1; } file_t out; if (!file_open_write(&out, f[1])) { fprintf(stderr, "Could not open mp3 file for write: %s\n", f[1]); file_close(&in); return 1; } aq_t qin, qout; aq_init(&qin); aq_init(&qout); mp3_frame_t frame; while (mp3_next_frame(&in, &frame) > 0) { static int cin = 0; printf("%d in frame_size %ld, backptr %d, adu_size %ld, cksum %ld\n", cin++, frame.frame_data_size, frame.si.main_data_end, frame.adu_size, cksum(frame.raw, frame.frame_size)); if (aq_add_frame(&qin, &frame)) { adu_t *adu = aq_get_adu(&qin); assert(adu != NULL); static int count = 0; if (count > 2000) break; if ((count++ % 25) <= 10) { free(adu); continue; } if (aq_add_adu(&qout, adu)) { mp3_frame_t *frame_out = aq_get_frame(&qout); assert(frame_out != NULL); static int cout = 0; memset(frame_out->raw, 0, 4 + frame_out->si_size); if (!mp3_fill_hdr(frame_out) || !mp3_fill_si(frame_out) || (mp3_write_frame(&out, frame_out) <= 0)) { fprintf(stderr, "Could not write frame\n"); file_close(&in); file_close(&out); return 1; } printf("%d out frame_size %ld, backptr %d, adu_size %ld, cksum %ld\n", cout++, frame_out->frame_data_size, frame_out->si.main_data_end, frame_out->adu_size, cksum(frame_out->raw, frame_out->frame_size)); free(frame_out); } free(adu); } // fgetc(stdin); } file_close(&in); file_close(&out); aq_destroy(&qin); aq_destroy(&qout); return 0; } #endif /* AQ2_TEST */ poc-0.4.2/dlist.h0000664000175000001440000000416610210123147014226 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef DLIST_H__ #define DLIST_H__ /*M \emph{Double-linked list node structure.} **/ typedef struct dlist_s { void *data; struct dlist_s *next; struct dlist_s *prev; } dlist_t; /*M \emph{Cast to a single operand list operation.} **/ #define DLIST_OP(f) (void (*)(void *))(f) /*M \emph{Cast to a dual operand list operation.} **/ #define DLIST_OP2(f) (int (*)(void *, void *))(f) /*M \emph{Double-linked list head structure.} **/ typedef struct dlist_head_s { struct dlist_s *dlist; struct dlist_s *end; unsigned int num; } dlist_head_t; /*C **/ void dlist_init(dlist_head_t *head); dlist_t *dlist_new(void *data); void dlist_free(dlist_t *dlist); void dlist_delete(dlist_t *dlist, void (*free)(void *)); void dlist_destroy(dlist_head_t *head, void (*free)(void *data)); int dlist_insl_after(dlist_head_t *head, dlist_t *dlist, dlist_t *new); int dlist_insl_before(dlist_head_t *head, dlist_t *dlist, dlist_t *new); dlist_t *dlist_ins_after(dlist_head_t *head, dlist_t *dlist, void *data); dlist_t *dlist_ins_before(dlist_head_t *head, dlist_t *dlist, void *data); int dlist_insl_end(dlist_head_t *head, dlist_t *dlist); int dlist_insl_front(dlist_head_t *head, dlist_t *dlist); dlist_t *dlist_ins_end(dlist_head_t *head, void *data); dlist_t *dlist_ins_front(dlist_head_t *head, void *data); dlist_t *dlist_getl(dlist_head_t *head, dlist_t *dlist); void *dlist_get(dlist_head_t *head, dlist_t *dlist); dlist_t *dlist_getl_end(dlist_head_t *head); dlist_t *dlist_getl_front(dlist_head_t *head); void *dlist_get_end(dlist_head_t *head); void *dlist_get_front(dlist_head_t *head); void *dlist_front(dlist_head_t *head); void *dlist_end(dlist_head_t *head); dlist_t *dlist_search(dlist_head_t *head, void *data, int (*cmp)(void *data, void *data2)); #define dlist_push(h, x) dlist_ins_front((h), (x)) #define dlist_pop(h) dlist_get_front((h)) #endif /* DLIST_H__ */ poc-0.4.2/http.h0000664000175000001440000000224210203412274014063 0ustar manuelusers00000000000000/* * HTTP server routines * * (c) 2005 bl0rg.net */ #ifndef HTTP_H__ #define HTTP_H__ /* Maximal size of HTTP header. */ #define HTTP_MAX_HDR_LEN 8192 /* Seconds before HTTP timeout. */ #define HTTP_TIMEOUT 20 /* Structure used to save information about HTTP clients. */ typedef struct http_client_s { int fd, found, in, len; char buf[HTTP_MAX_HDR_LEN]; time_t fini; } http_client_t; #define HTTP_MIN_CLIENTS 2 typedef int http_client_callback_t(http_client_t *client, void *data); typedef struct http_server_s { http_client_t *clients; unsigned int num_clients; unsigned int count_clients; unsigned int max_clients; http_client_callback_t *callback; int fd; } http_server_t; void http_server_reset(http_server_t *server); int http_server_init(http_server_t *server, unsigned int num_clients, unsigned int max_clients, http_client_callback_t *callback, int fd); int http_server_main(http_server_t *server, void *data); void http_server_close(http_server_t *server); int http_client_close(http_server_t *server, http_client_t *client); #endif /* HTTP_H__ */ poc-0.4.2/mp3-write.c0000664000175000001440000000776110210123147014735 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include #include #include "mp3.h" #include "bv.h" /*M **/ int mp3_fill_si(mp3_frame_t *frame) { assert(frame != NULL); assert((frame->si_bitsize != 0) || "Trying to write an empty sideinfo"); unsigned char *ptr = frame->raw + 4; if (frame->protected == 0) ptr += 2; bv_t bv; bv_init(&bv, ptr, frame->si_bitsize); mp3_si_t *si = &frame->si; unsigned int nch = (frame->mode != 3) ? 2 : 1; bv_put_bits(&bv, si->main_data_end, 9); bv_put_bits(&bv, si->private_bits, nch == 2 ? 3 : 5); unsigned int i; for (i = 0; i < nch; i++) { unsigned int band; for (band = 0; band < 4; band++) bv_put_bits(&bv, si->channel[i].scfsi[band], 1); } unsigned int gri; for (gri = 0; gri < 2; gri++) { for (i = 0; i < nch; i++) { mp3_granule_t *gr = &si->channel[i].granule[gri]; bv_put_bits(&bv, gr->part2_3_length, 12); bv_put_bits(&bv, gr->big_values, 9); bv_put_bits(&bv, gr->global_gain, 8); bv_put_bits(&bv, gr->scale_comp, 4); bv_put_bits(&bv, gr->blocksplit_flag, 1); if (gr->blocksplit_flag) { bv_put_bits(&bv, gr->block_type, 2); bv_put_bits(&bv, gr->switch_point, 1); bv_put_bits(&bv, gr->tbl_sel[0], 5); bv_put_bits(&bv, gr->tbl_sel[1], 5); unsigned int j; for (j = 0; j < 3; j++) bv_put_bits(&bv, gr->sub_gain[j], 3); } else { unsigned int j; for (j = 0; j < 3; j++) bv_put_bits(&bv, gr->tbl_sel[j], 5); bv_put_bits(&bv, gr->reg0_cnt, 4); bv_put_bits(&bv, gr->reg1_cnt, 3); } bv_put_bits(&bv, gr->preflag, 1); bv_put_bits(&bv, gr->scale_scale, 1); bv_put_bits(&bv, gr->cnt1tbl_sel, 1); } } assert((bv.len == bv.idx) || "Bitvector is not filled completely"); return 1; } extern unsigned long bitratetable[16]; extern unsigned short sampleratetable[4]; /*M **/ int mp3_fill_hdr(mp3_frame_t *frame) { assert(frame != NULL); bv_t bv; bv_init(&bv, frame->raw, 4 * 8); bv_put_bits(&bv, 0xFFF, 12); bv_put_bits(&bv, frame->id, 1); bv_put_bits(&bv, frame->layer, 2); bv_put_bits(&bv, frame->protected, 1); bv_put_bits(&bv, frame->bitrate_index, 4); bv_put_bits(&bv, frame->samplerfindex, 2); bv_put_bits(&bv, frame->padding_bit, 1); bv_put_bits(&bv, frame->private_bit, 1); bv_put_bits(&bv, frame->mode, 2); bv_put_bits(&bv, frame->mode_ext, 2); bv_put_bits(&bv, frame->copyright, 1); bv_put_bits(&bv, frame->original, 1); bv_put_bits(&bv, frame->emphasis, 2); if (frame->protected == 0) { frame->raw[4] = frame->crc[0]; frame->raw[5] = frame->crc[1]; } assert((bv.idx == bv.len) || "Bitvector is not filled completely"); mp3_calc_hdr(frame); return 1; } /*M **/ int mp3_write_frame(file_t *mp3, mp3_frame_t *frame) { assert(mp3 != NULL); assert(frame != NULL); if (file_write(mp3, frame->raw, frame->frame_size) <= 0) return EEOF; return 1; } /*C **/ #ifdef MP3_TEST int main(int argc, char *argv[]) { char *f[2]; if (!(f[0] = *++argv) || !(f[1] = *++argv)) { fprintf(stderr, "Usage: mp3-write mp3in mp3out\n"); return 1; } mp3_file_t in; if (!mp3_open_read(&in, f[0])) { fprintf(stderr, "Could not open mp3 file for read: %s\n", f[0]); return 1; } mp3_file_t out; if (!mp3_open_write(&out, f[1])) { fprintf(stderr, "Could not open mp3 file for write: %s\n", f[1]); mp3_close(&in); return 1; } mp3_frame_t frame; while (mp3_next_frame(&in, &frame) > 0) { memset(frame.raw, 0, 4 + frame.si_size); if (!mp3_fill_hdr(&frame) || !mp3_fill_si(&frame) || (mp3_write_frame(&out, &frame) <= 0)) { fprintf(stderr, "Could not write frame\n"); mp3_close(&in); mp3_close(&out); return 1; } } mp3_close(&in); mp3_close(&out); return 0; } #endif poc-0.4.2/radio.sh0000775000175000001440000000146110211653216014374 0ustar manuelusers00000000000000#!/bin/bash export PATH=$PATH:/usr/local/bin rtp_port=1500 rtp_host=224.0.1.23 rtp_cert= while [ $# -gt 0 ] do case "$1" in -h) rtp_host="$2"; shift;; -p) rtp_port="$2"; shift;; -c) rtp_cert="$2"; shift;; --) shift; break;; -*) echo >&2 \ "usage: $0 [-h rtp_host] [-p rtp_port] [-c rtp_cert] http_host http_port" exit 1;; *) break;; # terminate while loop esac shift done while true; do print -n "GET / HTTP/1.0\r\n\r\n" | nc $1 $2 | \ buffer | \ (if [ $rtp_cert ]; then ./poc -c $rtp_cert -p $rtp_port -s $rtp_host - else ./poc -p $rtp_port -s $rtp_host - fi;) print "Reconnecting..." sleep 120 done poc-0.4.2/mp3tools.ebuild0000664000175000001440000000065210210454347015711 0ustar manuelusers00000000000000 DESCRIPTION="toolset for cutting mp3 files" HOMEPAGE="http://bl0rg.net/software/poc/" SRC_URI="http://bl0rg.net/software/poc/poc-${PV}.tar.gz" SLOT="0" KEYWORDS="x86" DEPEND="" S="${WORKDIR}/${PN}-${PV}" src_compile() { emake || die "emake failed" } src_install() { dobin mp3cue dobin mp3cut dobin mp3length dobin README dodoc TODO doman man/man1/mp3cue.1 doman man/man1/mp3cut.1 doman man/man1/mp3length.1 } poc-0.4.2/network.c0000664000175000001440000000064610210123147014572 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" int net_seqnum_diff(unsigned long seq1, unsigned long seq2, unsigned long maxseq) { if (seq2 >= seq1) { if ((seq2 - seq1) < (maxseq / 2)) return seq2 - seq1; else return (seq2 - seq1) - maxseq; } else { int d = seq2 + maxseq - seq1; if (d < (maxseq / 2)) return d; else return d - maxseq; } } /*C **/ poc-0.4.2/adutomp3.c0000664000175000001440000000261710204101057014634 0ustar manuelusers00000000000000#include "conf.h" #include #include #include #include #include #include "pack.h" #include "aq.h" #include "file.h" #include "mp3.h" static void usage(void) { printf("Usage: adutomp3 adufile\n"); } int main(int argc, char *argv[]) { int retval = EXIT_SUCCESS; if (argc != 2) { usage(); return EXIT_FAILURE; } file_t infile; aq_t qin; aq_init(&qin); if (!file_open_read(&infile, argv[1])) { fprintf(stderr, "Could not open adu file: %s\n", argv[1]); retval = EXIT_FAILURE; goto exit; } int ret; for (;;) { adu_t adu; unsigned char len[2]; unsigned char *ptr = len; ret = file_read(&infile, len, 2); if (ret != 2) break; adu.adu_size = UINT16_UNPACK(ptr); ret = file_read(&infile, adu.raw, adu.adu_size); if (ret != adu.adu_size) break; if (!mp3_read_hdr(&adu) || !mp3_read_si(&adu)) { fprintf(stderr, "Could not read adu\n"); break; } if (aq_add_adu(&qin, &adu)) { mp3_frame_t *frame = aq_get_frame(&qin); assert(frame != NULL); if (!mp3_fill_hdr(frame) || !mp3_fill_si(frame)) { assert(NULL); } ret = write(STDOUT_FILENO, frame->raw, frame->frame_size); assert(ret == frame->frame_size); free(frame); } } file_close(&infile); exit: aq_destroy(&qin); return retval; } poc-0.4.2/conf.h0000664000175000001440000000030610210123147014024 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef CONF_H__ #define CONF_H__ #ifdef __linux__ #define NEED_GETOPT_H__ #endif /* linux */ #ifdef __APPLE__ #endif /* __APPLE__ */ /*C **/ #endif /* CONF_H__ */ poc-0.4.2/mp3length.c0000664000175000001440000000265310201724101014777 0ustar manuelusers00000000000000#include "conf.h" #include #include #include #include #include #include "file.h" #include "mp3.h" #include "aq.h" static void usage(void) { fprintf(stderr, "Usage: mp3length mp3file\n"); } static void format_time(unsigned long time, char *str, unsigned int len) { unsigned long ms = time % 1000; time /= 1000; unsigned long secs = time % 60; time /= 60; unsigned long minutes = time; time /= 60; unsigned long hours = time; snprintf(str, len, "%.2lu:%.2lu:%.2lu+%.3lu", hours, minutes, secs, ms); } int main(int argc, char *argv[]) { int retval = EXIT_SUCCESS; if (argc != 2) { usage(); return EXIT_FAILURE; } file_t mp3file; if (!file_open_read(&mp3file, argv[1])) { fprintf(stderr, "Could not open mp3 file: %s\n", argv[1]); retval = EXIT_FAILURE; goto exit; } aq_t qin; aq_init(&qin); mp3_frame_t frame; int ret; unsigned long long time = 0; while ((ret = mp3_next_frame(&mp3file, &frame)) > 0) { if (aq_add_frame(&qin, &frame)) { adu_t *adu = aq_get_adu(&qin); assert(adu != NULL); time += adu->usec; free(adu); } } file_close(&mp3file); aq_destroy(&qin); char buf[256]; format_time(time / 1000, buf, sizeof(buf)); printf("Length of %s: %s\n", argv[1], buf); exit: return retval; } poc-0.4.2/Makefile0000664000175000001440000003213310214014115014367 0ustar manuelusers00000000000000# GNU Makefile for poc, mp3cue, mp3cut # # Please compile with GNU make. # # 2005 bl0rg.net CFLAGS += -Wall -O2 # Uncomment these flags to add id3 support to mp3cue and mp3cut #CFLAGS += -DWITH_ID3TAG #LDFLAGS += -lid3tag # On MacOSX using fink #CFLAGS += -I/sw/include #LDFLAGS += -L/sw/lib # Uncomment this flag to add ipv6 support to poc #CFLAGS+=-DWITH_IPV6 # Uncomment these flags to add SSL support to poc #CFLAGS+=-DWITH_OPENSSL #LDFLAGS+=-lssl -lcrypto # Uncomment these flags to debug #CFLAGS += -g #CFLAGS+=-DDEBUG #CFLAGS+=-DMALLOC -ldmalloc TEXIFY := ./texify.pl FLEX=flex FLEX_LIBS=-lfl # Use these definitions when using bison YACC=bison -b y # Use these definitions when using yacc #YACC=yacc #LIBS+=-ly all: servers clients mp3cue mp3cut mp3length # Create dependencies %.d: %.c $(CC) -MM $(CFLAGS) $< > $@ $(CC) -MM $(CFLAGS) $< | sed s/\\.o/.d/ >> $@ MP3_OBJS := mp3-read.o mp3-write.o mp3.o aq.o id3.o NETWORK_OBJS := network.o network4.o network6.o RTP_OBJS := rtp.o rtp-rb.o UTILS_OBJS := pack.o bv.o signal.o dlist.o file.o buf.o crc32.o misc.o FEC_OBJS := galois.o matrix.o fec.o fec-pkt.o fec-rb.o fec-group.o OGG_OBJS := ogg.o vorbis.o ogg-read.o ogg-write.o vorbis-read.o OBJS := $(MP3_OBJS) \ $(OGG_OBJS) \ $(NETWORK_OBJS) \ $(RTP_OBJS) \ $(UTILS_OBJS) \ $(FEC_OBJS) DEPS := $(patsubst %.o,%.d,$(OBJS)) include $(DEPS) # mp3cue MP3CUE_OBJS := $(MP3_OBJS) $(UTILS_OBJS) \ mp3cue-lex.yy.o mp3cue-y.tab.o mp3cue-main.o include mp3cue-main.d mp3cue-lex.yy.c: mp3cue.l $(FLEX) -o$@ $< mp3cue-lex.yy.o: mp3cue-lex.yy.c mp3cue-y.tab.c $(CC) -c -o $@ mp3cue-lex.yy.c mp3cue-y.tab.c: mp3cue.y $(YACC) -d -o $@ $< mp3cue: $(MP3CUE_OBJS) $(CC) $(CFLAGS) -o mp3cue $(MP3CUE_OBJS) \ $(LDFLAGS) $(LIBS) $(FLEX_LIBS) mp3cue-clean: - rm -rf $(MP3CUE_OBJS) \ mp3cue-lex.yy.c mp3cue-y.tab.c mp3cue-y.tab.h \ mp3cue mp3cue.exe # mp3cut MP3CUT_OBJS := $(MP3_OBJS) $(UTILS_OBJS) mp3cut.o include mp3cut.d mp3cut: $(MP3CUT_OBJS) $(CC) $(CFLAGS) -o mp3cut $(MP3CUT_OBJS) $(LDFLAGS) $(LIBS) mp3cut-clean: - rm -rf $(MP3CUT_OBJS) mp3cut mp3cut.exe MP3LENGTH_OBJS := $(MP3_OBJS) $(UTILS_OBJS) mp3length.o include mp3length.d mp3length: $(MP3LENGTH_OBJS) $(CC) $(CFLAGS) -o mp3length $(MP3LENGTH_OBJS) $(LDFLAGS) $(LIBS) mp3length-clean: - rm -rf $(MP3LENGTH_OBJS) mp3length mp3length.exe # Servers SERVERS := poc-2250 \ poc-3119 \ poc-2250-ploss \ poc-3119-ploss \ poc-fec \ poc-fec-ploss \ poc-http \ pogg-http SERVERS_EXE := $(patsubst %,%.exe,$(SERVERS)) SERVERS_OBJS := servers: $(SERVERS) MP3RTP_OBJS := $(NETWORK_OBJS) $(MP3_OBJS) $(RTP_OBJS) $(UTILS_OBJS) # RFC 2250 protocol POC_2250_OBJS := $(MP3RTP_OBJS) poc-2250.o include poc-2250.d poc-2250: $(POC_2250_OBJS) $(CC) $(CFLAGS) -o poc-2250 $(POC_2250_OBJS) $(LDFLAGS) $(LIBS) POC_2250_PLOSS_OBJS := $(MP3RTP_OBJS) poc-2250-ploss.o poc-2250-ploss.o: poc-2250.c $(CC) $(CFLAGS) -DDEBUG_PLOSS -c -o $@ $< poc-2250-ploss: $(POC_2250_PLOSS_OBJS) $(CC) $(CFLAGS) -o $@ $(POC_2250_PLOSS_OBJS) $(LDFLAGS) $(LIBS) SERVERS_OBJS += $(POC_2250_OBJS) $(POC_2250_PLOSS_OBJS) # RFC 3119 protocol POC_3119_OBJS := $(MP3RTP_OBJS) poc-3119.o include poc-3119.d poc-3119: $(POC_3119_OBJS) $(CC) $(CFLAGS) -o poc-3119 $(POC_3119_OBJS) $(LDFLAGS) $(LIBS) POC_3119_PLOSS_OBJS := $(MP3RTP_OBJS) poc-3119-ploss.o poc-3119-ploss.o: poc-3119.c $(CC) $(CFLAGS) -DDEBUG_PLOSS -c -o $@ $< poc-3119-ploss: $(POC_3119_PLOSS_OBJS) $(CC) $(CFLAGS) -o $@ $(POC_3119_PLOSS_OBJS) $(LDFLAGS) $(LIBS) SERVERS_OBJS += $(POC_3119_OBJS) $(POC_3119_PLOSS_OBJS) # FEC protocol MP3FEC_OBJS := $(MP3_OBJS) $(NETWORK_OBJS) $(UTILS_OBJS) $(FEC_OBJS) POC_FEC_OBJS := $(MP3FEC_OBJS) poc-fec.o include poc-fec.d poc-fec: $(POC_FEC_OBJS) $(CC) $(CFLAGS) -o $@ $(POC_FEC_OBJS) $(LDFLAGS) $(LIBS) POC_FEC_PLOSS_OBJS := $(MP3FEC_OBJS) poc-fec-ploss.o poc-fec-ploss.o: poc-fec.c $(CC) $(CFLAGS) -DDEBUG_PLOSS -c -o $@ $< poc-fec-ploss: $(POC_FEC_PLOSS_OBJS) $(CC) $(CFLAGS) -o $@ $(POC_FEC_PLOSS_OBJS) $(LDFLAGS) $(LIBS) SERVERS_OBJS += $(POC_FEC_OBJS) $(POC_FEC_PLOSS_OBJS) # mp3 and ogg HTTP server POC_HTTP_OBJS := $(MP3_OBJS) $(NETWORK_OBJS) $(UTILS_OBJS) http.o poc-http.o include poc-http.d poc-http: $(POC_HTTP_OBJS) $(CC) $(CFLAGS) -o $@ $(POC_HTTP_OBJS) $(LDFLAGS) $(LIBS) SERVERS_OBJS += $(POC_HTTP_OBJS) POGG_HTTP_OBJS := $(OGG_OBJS) $(NETWORK_OBJS) $(UTILS_OBJS) http.o pogg-http.o include pogg-http.d pogg-http: $(POGG_HTTP_OBJS) $(CC) $(CFLAGS) -o $@ $(POGG_HTTP_OBJS) $(LDFLAGS) $(LIBS) SERVERS_OBJS += $(POGG_HTTP_OBJS) servers-clean: - rm -f $(SERVERS) $(SERVERS_EXE) $(SERVERS_OBJS) # Clients CLIENTS := pob-fec \ pob-3119 \ pob-2250 CLIENTS_EXE := $(patsubst %,%.exe,$(CLIENTS)) clients: $(CLIENTS) RTP_CLIENT_OBJS := $(RTP_OBJS) $(NETWORK_OBJS) $(UTILS_OBJS) $(MP3_OBJS) # RFC 2250 client POB_2250_RB_OBJS := $(RTP_CLIENT_OBJS) pob-2250-rb.o include pob-2250-rb.d pob-2250: $(POB_2250_RB_OBJS) $(CC) $(CFLAGS) -o $@ $(POB_2250_RB_OBJS) $(LDFLAGS) $(LIBS) CLIENTS_OBJS += $(POB_2250_OBJS) $(POB_2250_RB_OBJS) # RFC 3119 client POB_3119_RB_OBJS := $(RTP_CLIENT_OBJS) pob-3119-rb.o include pob-3119-rb.d pob-3119: $(POB_3119_RB_OBJS) $(CC) $(CFLAGS) -o $@ $(POB_3119_RB_OBJS) $(LDFLAGS) $(LIBS) CLIENTS_OBJS += $(POB_3119_OBJS) $(POB_3119_RB_OBJS) # FEC client POB_FEC_OBJS := $(NETWORK_OBJS) $(FEC_OBJS) $(UTILS_OBJS) $(MP3_OBJS) pob-fec.o include pob-fec.d pob-fec: $(POB_FEC_OBJS) $(CC) $(CFLAGS) -o $@ $(POB_FEC_OBJS) $(LDFLAGS) $(LIBS) CLIENTS_OBJS += $(POB_FEC_OBJS) clients-clean: - rm -f $(CLIENTS) $(CLIENTS_EXE) $(CLIENTS_OBJS) # Tools MP3TOADU_OBJS := $(UTILS_OBJS) $(MP3_OBJS) mp3toadu.o include mp3toadu.d mp3toadu: $(MP3TOADU_OBJS) $(CC) $(CFLAGS) -o $@ $(MP3TOADU_OBJS) $(LDFLAGS) $(LIBS) ADUTOMP3_OBJS := $(UTILS_OBJS) $(MP3_OBJS) adutomp3.o include adutomp3.d adutomp3: $(ADUTOMP3_OBJS) $(CC) $(CFLAGS) -o $@ $(ADUTOMP3_OBJS) $(LDFLAGS) $(LIBS) # Tests bvtest: bv.c bv.h $(CC) $(CFLAGS) -o $@ -DBV_TEST bv.c $(LDFLAGS) crc32test: crc32.h crc32.c $(CC) $(CFLAGS) -o $@ -DCRC32_TEST crc32.c $(LDFLAGS) packtest: pack.c pack.h $(CC) $(CFLAGS) -o $@ -DPACK_TEST pack.c $(LDFLAGS) dlisttest: dlist.c dlist.h $(CC) $(CFLAGS) -o $@ -DDLIST_TEST dlist.c $(LDFLAGS) galoistest: galois.c galois.h $(CC) $(CFLAGS) -o $@ -DGALOIS_TEST galois.c $(LDFLAGS) matrixtest: matrix.c matrix.h galois.o $(CC) $(CFLAGS) -o $@ -DMATRIX_TEST matrix.c galois.o $(LDFLAGS) fectest: fec.c fec.h galois.o matrix.o $(CC) $(CFLAGS) -o $@ -DFEC_TEST fec.c matrix.o galois.o $(LDFLAGS) rtptest: rtp.c rtp.h pack.o pack.h $(CC) $(CFLAGS) -o $@ -DRTP_TEST rtp.c pack.o $(LDFLAGS) ogg-readtest: ogg-read.c ogg.o crc32.o file.o buf.o pack.o $(CC) $(CFLAGS) -o $@ -DDEBUG -DOGG_TEST ogg-read.c ogg.o crc32.o \ file.o buf.o pack.o ogg-writetest: ogg-write.c ogg-read.c ogg.o crc32.o file.o buf.o pack.o $(CC) $(CFLAGS) -o $@ -DDEBUG -DOGG_WRITETEST ogg-write.c ogg-read.c\ ogg.o crc32.o \ file.o buf.o pack.o vorbis-readtest: vorbis-read.c vorbis.o ogg.o crc32.o file.o buf.o pack.o \ ogg-read.o bv.o $(CC) $(CFLAGS) -o $@ -DDEBUG -DVORBIS_TEST vorbis-read.c vorbis.o \ ogg.o ogg-read.o crc32.o file.o buf.o pack.o \ bv.o mp3-readtest: mp3-read.c mp3.h bv.o bv.h mp3.o mp3-sf.o $(CC) $(CFLAGS) -o $@ -DMP3_TEST mp3-read.c bv.o mp3.o mp3-sf.o \ $(LDFLAGS) mp3-writetest: mp3-write.c mp3-read.o mp3.h bv.o bv.h mp3.o mp3-sf.o $(CC) $(CFLAGS) -o $@ -DMP3_TEST mp3-write.c bv.o mp3-read.o mp3.o \ mp3-sf.o $(LDFLAGS) mp3-sftest: mp3-sf.c mp3-write.o mp3-read.o mp3.h bv.o bv.h mp3.o aq.o dlist.o $(CC) $(CFLAGS) -o $@ -DMP3SF_TEST mp3-sf.c mp3-write.o bv.o \ mp3-read.o mp3.o aq.o dlist.o $(LDFLAGS) mp3-transtest: mp3-trans.c mp3-read.o mp3-write.o mp3.h bv.o bv.h \ mp3.o mp3-sf.o $(CC) $(CFLAGS) -o $@ -DMP3_TEST mp3-trans.c bv.o mp3-read.o \ mp3.o mp3-write.o mp3-sf.o $(LDFLAGS) aq1test: aq.c aq.h dlist.o dlist.h mp3-read.o mp3.h bv.h bv.o mp3.o mp3-sf.o $(CC) $(CFLAGS) -o $@ -DAQ1_TEST aq.c mp3-read.o bv.o mp3.o dlist.o \ mp3-sf.o $(LDFLAGS) aq2test: aq.c aq.h dlist.o dlist.h mp3-read.o mp3.h bv.h bv.o mp3.o \ mp3-write.o mp3-sf.o file.o $(CC) $(CFLAGS) -o $@ -DAQ2_TEST aq.c mp3-read.o bv.o mp3.o dlist.o \ mp3-write.o mp3-sf.o file.o $(LDFLAGS) TESTS = bvtest packtest dlisttest rtptest mp3-readtest mp3-writetest \ mp3-sftest mp3-transtest aq1test aq2test galoistest matrixtest \ fectest crc32test ogg-readtest tests: test.sh $(TESTS) ./test.sh $(TESTS) tests-clean: - rm -f $(TESTS) # Tex tex/aq.tex: aq.h aq.c $(TEXIFY) aq.h aq.c > $@ tex/bv.tex: bv.h bv.c $(TEXIFY) bv.h bv.c > $@ tex/mp3.tex: mp3.h mp3.c mp3-read.c mp3-write.c $(TEXIFY) mp3.h mp3.c mp3-read.c mp3-write.c > $@ tex/rtp.tex: rtp.h rtp.c $(TEXIFY) rtp.h rtp.c > $@ tex/rtp-rb.tex: rtp-rb.h rtp-rb.c $(TEXIFY) rtp-rb.h rtp-rb.c > $@ tex/dlist.tex: dlist.h dlist.c $(TEXIFY) dlist.h dlist.c > $@ tex/pack.tex: pack.h pack.c $(TEXIFY) pack.h pack.c > $@ tex/network.tex: network.h network.c $(TEXIFY) network.h network.c > $@ tex/errorlog.tex: errorlog2tex.pl errorlog.txt ./errorlog2tex.pl errorlog.txt > $@ tex/matrix.tex: matrix.h matrix.c $(TEXIFY) matrix.h matrix.c > $@ tex/galois.tex: galois.h galois.c $(TEXIFY) galois.h galois.c > $@ tex/fec.tex: fec.h fec.c $(TEXIFY) fec.h fec.c > $@ tex/fec-pkt.tex: fec-pkt.h fec-pkt.c $(TEXIFY) fec-pkt.h fec-pkt.c > $@ tex/fec-group.tex: fec-group.h fec-group.c $(TEXIFY) fec-group.h fec-group.c > $@ tex/fec-rb.tex: fec-rb.h fec-rb.c $(TEXIFY) fec-rb.h fec-rb.c > $@ tex/poc-2250.tex: poc-2250.c $(TEXIFY) poc-2250.c > $@ tex/pob-2250.tex: pob-2250.c $(TEXIFY) pob-2250.c > $@ tex/pob-2250-rb.tex: pob-2250-rb.c $(TEXIFY) pob-2250-rb.c > $@ tex/poc-3119.tex: poc-3119.c $(TEXIFY) poc-3119.c > $@ tex/pob-3119.tex: pob-3119.c $(TEXIFY) pob-3119.c > $@ tex/pob-3119-rb.tex: pob-3119-rb.c $(TEXIFY) pob-3119-rb.c > $@ tex/poc-fec.tex: poc-fec.c $(TEXIFY) poc-fec.c > $@ tex/pob-fec.tex: pob-fec.c pob-fec.h $(TEXIFY) pob-fec.h pob-fec.c > $@ tex/poc-http.tex: poc-http.c $(TEXIFY) poc-http.c > $@ tex/huffman.tex: huffman.pl ./pod2latex.pl -out $@ $< TEXS = tex/aq.tex tex/mp3.tex tex/rtp.tex tex/dlist.tex tex/pack.tex \ tex/network.tex tex/bv.tex tex/galois.tex \ tex/matrix.tex tex/fec.tex tex/poc-2250.tex tex/pob-2250.tex \ tex/poc-3119.tex tex/pob-3119.tex tex/poc-fec.tex tex/pob-fec.tex \ tex/poc-http.tex tex/fec-pkt.tex tex/rtp-rb.tex tex/fec-group.tex \ tex/fec-rb.tex tex/pob-3119-rb.tex tex/pob-2250-rb.tex tex/poc-http.tex STUDIENTEXS = tex/einleitung.tex tex/implementation.tex \ tex/streaming.tex tex/studienarbeit.tex tex/transcoding.tex \ tex/uebersicht.tex tex/fecsec.tex tex/zusammenfassung.tex tex/test.pdf: tex/test.tex $(TEXS) cd tex; pdflatex test.tex; cd .. tex/studienarbeit.pdf: $(STUDIENTEXS) $(TEXS) cd tex; pdflatex studienarbeit.tex; cd .. tex/code.pdf: tex/code.tex $(TEXS) cd tex; pdflatex code.tex; cd .. tex-clean: - rm -f $(TEXS) tex/studienarbeit.pdf tex/code.pdf tex/*.aux tex/*.log dep-clean: - rm -f *.d clean: tests-clean \ clients-clean \ servers-clean \ tex-clean \ mp3cue-clean \ mp3cut-clean \ mp3length-clean \ dep-clean USER ?= root GROUP ?= root PREFIX:= /usr/local install: install-man mkdir -p $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 mp3cue $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 mp3cut $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 mp3length $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 pob-2250 $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 pob-3119 $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 pob-fec $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 poc-2250 $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 poc-3119 $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 poc-fec $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 poc-http $(DESTDIR)/$(PREFIX)/bin install -g $(GROUP) -o $(USER) -m 0755 pogg-http $(DESTDIR)/$(PREFIX)/bin install-man: mkdir -p $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/mp3cue.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/mp3cut.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/mp3length.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/pob-2250.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/pob-3119.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/pob-fec.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/poc-2250.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/poc-3119.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/poc-fec.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/poc-http.1 $(DESTDIR)/$(PREFIX)/share/man/man1 install -g $(GROUP) -o $(USER) -m 0644 man/man1/pogg-http.1 $(DESTDIR)/$(PREFIX)/share/man/man1 poc-0.4.2/fec.c0000664000175000001440000001404210210123147013631 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include #include #include #include "fec.h" #include "matrix.h" #ifdef DEBUG #include #endif /*M \emph{Free a FEC parameter structure.} **/ void fec_free(fec_t *fec) { assert(fec != NULL); assert(fec->gen_matrix != NULL); free(fec->gen_matrix); free(fec); } /*M \emph{Initialize a FEC parameter structure.} Create a generator matrix. % XXX Documentation for generator matrix **/ fec_t *fec_new(unsigned int k, unsigned int n) { assert((k <= n ) || "k is too big"); assert((k <= 256) || "k is too big"); assert((n <= 256) || "n is too big"); /*M Init Galois arithmetic if not already initialized. **/ static int gf_initialized = 0; if (!gf_initialized) { gf_init(); gf_initialized = 1; } fec_t *res; res = malloc(sizeof(fec_t)); assert(res != NULL); res->gen_matrix = malloc(sizeof(gf)*k*n); assert(res->gen_matrix != NULL); res->k = k; res->n = n; /*M Fill the matrix with powers of field elements. **/ gf tmp[k*n]; /* gf *tmp = res->gen_matrix; */ /*M First row is special (powers of $0$). **/ tmp[0] = 1; unsigned int col; for (col = 1; col < k; col++) tmp[col] = 0; gf *p; unsigned int row; for (p = tmp + k, row = 0; row < n - 1; row++, p += k) { for (col = 0; col < k; col++) p[col] = gf_polys[(row * col) % 255]; } #ifdef DEBUG fprintf(stderr, "first vandermonde matrix\n"); matrix_print(tmp, res->n, res->k); #endif /*M Invert the upper $k \times k$ vandermonde matrix. **/ matrix_inv_vandermonde(tmp, k); #ifdef DEBUG fprintf(stderr, "\ninverted vandermonde matrix\n"); matrix_print(tmp, res->n, res->k); #endif /*M Multiply the inverted upper $k \times k$ vandermonde matrix with the lower band of the matrix. **/ matrix_mul(tmp + k * k, tmp, res->gen_matrix + k * k, n - k, k, k); /*M Fill the upper $k \times k$ matrix with the identity matrix to generate a systematic matrix. **/ for (row = 0; row < k; row++) for (col = 0; col < k; col++) if (col == row) res->gen_matrix[row * k + col] = 1; else res->gen_matrix[row * k + col] = 0; #ifdef DEBUG fprintf(stderr, "\ngenerated matrix\n"); matrix_print(res->gen_matrix, res->n, res->k); #endif return res; } /*M \emph{Produce encoded output packet.} Encodes the \verb|idx|'th output data packet from the \verb|k| data packets in \verb|src| and the generator matrix in \verb|fec|. For \verb|idx| $<$ \verb|k|, we just copy the data (systematic matrix). **/ void fec_encode(fec_t *fec, gf *src[], gf *dst, unsigned int idx, unsigned int len) { assert((idx < fec->n) || "Index of output packet to high"); if (idx < fec->k) { memcpy(dst, src[idx], len * sizeof(gf)); } else { gf *p = fec->gen_matrix + idx * fec->k; bzero(dst, len * sizeof(gf)); unsigned int i; for (i = 0; i < fec->k; i++) gf_add_mul(dst, src[i], p[i], len); } } /*M \emph{Builds the decoding matrix.} Builds the decoding matrix into \verb|matrix| out of the indexes stored in \verb|idxs|. Returns 0 on error, 1 on success. **/ int fec_decode_matrix(fec_t *fec, gf *matrix, unsigned int idxs[]) { gf *p; unsigned int i; for (p = matrix, i = 0; i < fec->k; i++, p += fec->k) { assert((idxs[i] < fec->n) || "index of packet to high for FEC"); memcpy(p, fec->gen_matrix + idxs[i] * fec->k, fec->k * sizeof(gf)); } #ifdef DEBUG matrix_print(matrix, fec->k, fec->k); #endif if (!matrix_inv(matrix, fec->k)) return 0; return 1; } /*M \emph{Put straight packets at the right place.} Packets with index $<$ k are put at the right place. **/ static int fec_shuffle(fec_t *fec, unsigned int idxs[]) { unsigned int i; for (i = 0; i < fec->k; ) { if ((idxs[i] >= fec->k) || (idxs[i] == i)) { i++; } else { unsigned int c = idxs[i]; /* check for conflicts */ if (idxs[c] == c) return 0; idxs[i] = idxs[c]; idxs[c] = c; } } return 1; } /*M \emph{Decode the received packets.} % XXXX **/ int fec_decode(fec_t *fec, gf *pkts, unsigned int idxs[], unsigned len) { assert(fec != NULL); if (!fec_shuffle(fec, idxs)) return 0; /*M Build decoding matrix. **/ gf dec_matrix[fec->k * fec->k]; if (!fec_decode_matrix(fec, dec_matrix, idxs)) return 0; unsigned int row; for (row = 0; row < fec->k; row++) { if (idxs[row] >= fec->k) { gf *pkt = pkts + row * len; bzero(pkt, len * sizeof(gf)); unsigned int col; for (col = 0; col < fec->k; col++) { gf_add_mul(pkt, pkts + idxs[col] * len, dec_matrix[row * fec->k + col], len); } } } return 1; } /*C **/ #ifdef FEC_TEST #include void testit(char *name, unsigned int result, unsigned int should) { if (result == should) { printf("Test %s was successful\n", name); } else { printf("Test %s was not successful, %u should have been %u\n", name, result, should); } } int main(void) { fec_t *fec; gf_init(); fec = fec_new(4, 8); printf("\n"); gf src_pkts[4][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16} }; gf dst_pkts[8 * 4]; gf *src_ptrs[4] = { src_pkts[0], src_pkts[1], src_pkts[2], src_pkts[3] }; unsigned int idxs[4] = {3, 5, 1, 0}; /* from 0 ?? */ int i; for (i = 0; i < 8; i++) { fec_encode(fec, src_ptrs, dst_pkts + i * 4, i, 4); int j; for (j = 0; j < 4; j++) printf("%u ", dst_pkts[i * 4 + j]); printf("\n"); } memset(dst_pkts + 2 * 4, 0, 4); memset(dst_pkts + 4 * 4, 0, 4); memset(dst_pkts + 6 * 4, 0, 4); memset(dst_pkts + 7 * 4, 0, 4); testit("fec decode", fec_decode(fec, dst_pkts, idxs, 4), 1); for (i = 0; i < 4; i++) { int j; for (j = 0; j < 4; j++) testit("fec decode", dst_pkts[i * 4 + j], src_pkts[i][j]); } fec_free(fec); return 0; } #endif /* FEC_TEST */ poc-0.4.2/fec-rb.c0000664000175000001440000000744010214014115014234 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include "fec-group.h" /*M \emph{Maximal number of elements in the ring buffer.} **/ unsigned int fec_rb_size = 0; /*M \emph{Index of first valid element in ring buffer.} **/ static unsigned int fec_rb_start = 0; /*M \emph{Index of first invalid element in ring buffer.} **/ static unsigned int fec_rb_end = 0; /*M \emph{Number of elements in the ring buffer.} **/ unsigned int fec_rb_cnt = 0; /*M \emph{Ring buffer array.} **/ fec_group_t *fec_rb = NULL; void fec_rb_clear(void) { fec_rb_start = 0; fec_rb_end = 0; fec_rb_cnt = 0; int i; for (i = 0; i < fec_rb_size; i++) fec_group_clear(fec_rb + i); } void fec_rb_pop(void) { assert(fec_rb != NULL); assert(fec_rb_end != fec_rb_start); fec_group_destroy(fec_rb + fec_rb_start); fec_rb_start = (fec_rb_start + 1) % fec_rb_size; fec_rb_cnt--; } void fec_rb_destroy(void) { if (fec_rb != NULL) { while (fec_rb_cnt) fec_rb_pop(); free(fec_rb); fec_rb = NULL; } fec_rb_size = 0; fec_rb_clear(); } void fec_rb_init(unsigned int size) { fec_rb_destroy(); fec_rb = malloc(sizeof(fec_group_t) * size); assert(fec_rb != NULL); int i; for (i = 0; i < fec_rb_size; i++) fec_group_clear(fec_rb + i); fec_rb_size = size; fec_rb_clear(); } unsigned int fec_rb_length(void) { assert(fec_rb != NULL); if (fec_rb_end >= fec_rb_start) return fec_rb_end - fec_rb_start; else return fec_rb_end + (fec_rb_size - fec_rb_start); } int fec_rb_insert_pkt(fec_pkt_t *pkt, int idx) { assert(pkt != NULL); assert(fec_rb != NULL); #ifdef DEBUG fprintf(stderr, "insert packet at idx %d, gseq %d, pseq %d\n", idx, pkt->hdr.group_seq, pkt->hdr.packet_seq); #endif if (idx < 0) { /* try to grow the buffer downwards */ if ((fec_rb_length() - idx) <= fec_rb_size) { fec_rb_start = (fec_rb_start + idx) % fec_rb_size; idx = 0; } else /* drop the packet silently */ return 0; } else if (idx >= fec_rb_size - 1) { /* not enough place left in ring buffer */ return 0; } fec_group_t *dst_group = fec_rb + ((idx + fec_rb_start) % fec_rb_size); if (dst_group->buf != NULL) { assert(dst_group->seq == pkt->hdr.group_seq); fec_group_insert_pkt(dst_group, pkt); } else { assert(dst_group->pkts == NULL); fec_group_init(dst_group, pkt->hdr.fec_k, pkt->hdr.fec_n, pkt->hdr.group_seq, pkt->hdr.group_tstamp, pkt->hdr.fec_len); fec_group_insert_pkt(dst_group, pkt); fec_rb_cnt++; } #ifdef DEBUG fprintf(stderr, "packet inserted at %d, end: %d\n", (idx + fec_rb_start) % fec_rb_size, fec_rb_end); #endif /* adjust the end pointer */ if (idx >= fec_rb_length()) fec_rb_end = ((idx + fec_rb_start + 1) % fec_rb_size); assert(fec_rb_start != fec_rb_end); /* XXX kann anscheinend auch passieren wenn wraparound. Generell muessen hier alle asserts abgefangen werden und mit einer error struktur sauber verarbeitet werden. */ assert(fec_rb[fec_rb_end].buf == NULL); return 1; } void fec_rb_print(void) { assert(fec_rb != NULL); fprintf(stderr, "start: %.3u, end: %.3u, len: %.3u\n", fec_rb_start, fec_rb_end, fec_rb_length()); } void fec_rb_print_rb(void) { unsigned int i; for (i = fec_rb_start; i != fec_rb_end; i = (i + 1) % fec_rb_size) { if (fec_rb[i].buf != NULL) fprintf(stderr, "%.3u: seq %.3u\n", i, fec_rb[i].seq); } } fec_group_t *fec_rb_first(void) { assert(fec_rb != NULL); if (fec_rb_start == fec_rb_end) return NULL; /* first should always be the first in buffer */ return fec_rb + fec_rb_start; } poc-0.4.2/network.h0000664000175000001440000000353410211673061014604 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef NET_H__ #define NET_H__ #include "netinet/in.h" int net_ip4_resolve_hostname(const char *hostname, unsigned short port, unsigned char ip[4], struct sockaddr_in *saddr); int net_udp4_socket(struct sockaddr_in *saddr, unsigned short port, unsigned char ttl); int net_udp4_send_socket(char *hostname, unsigned short port, unsigned char ttl); int net_udp4_recv_socket(char *hostname, unsigned short port); int net_tcp4_nonblock_socket(void); int net_tcp4_socket_nonblock(int s); int net_tcp4_bind(int s, unsigned char ip[4], unsigned short port); int net_tcp4_bind_reuse(int s, unsigned char ip[4], unsigned short port); int net_tcp4_listen_socket(char *hostname, unsigned short port); int net_tcp4_accept_socket(int s, unsigned char ip[4], unsigned short *port); #ifdef WITH_IPV6 int net_udp6_send_socket(char *hostname, unsigned short port, unsigned int hops); int net_udp6_recv_socket(char *hostname, unsigned short port); int net_tcp6_nonblock_socket(void); int net_tcp6_socket_nonblock(int s); int net_tcp6_bind(int s, unsigned char ip[4], unsigned short port); int net_tcp6_bind_reuse(int s, unsigned char ip[4], unsigned short port); int net_tcp6_listen_socket(char *hostname, unsigned short port); int net_tcp6_accept_socket(int s, unsigned char ip[16], unsigned short *port); #endif int net_seqnum_diff(unsigned long seq1, unsigned long seq2, unsigned long maxseq); /*C **/ #endif /* NET_H__ */ poc-0.4.2/mp3.c0000664000175000001440000000306110210123147013572 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include "mp3.h" /*M \emph{Bitrate table for MPEG Audio Layer III version 1.0.} Free format MP3s are considered invalid (for now). **/ unsigned long bitratetable[16] = { -1, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320, -1 }; /*M \emph{Samplerate table for MPEG Audio Layer III version 1.0.} **/ unsigned short sampleratetable[4] = { 44100, 48000, 32000, -1 }; /*M \emph{Calculate various information about the MP3 frame.} \verb|frame size| and \verb|frame data size| are given in bytes. \verb|frame data size| is the size of the MP3 frame without header and without side information. **/ void mp3_calc_hdr(mp3_frame_t *frame) { assert(frame != NULL); frame->bitrate = bitratetable[frame->bitrate_index]; frame->samplerate = sampleratetable[frame->samplerfindex]; frame->samplelen = 1152; /* only layer III */ frame->si_size = frame->mode != (unsigned char)3 ? 32 : 17; frame->si_bitsize = frame->si_size * 8; /* calculate frame length */ frame->frame_size = 144000 * frame->bitrate; frame->frame_size /= frame->samplerate; frame->frame_size += frame->padding_bit; frame->frame_data_size = frame->frame_size - 4 - frame->si_size; if (frame->protected == 0) frame->frame_data_size -= 2; frame->usec = (double)frame->frame_size * 8 * 1000.0 / ((double)frame->bitrate); } unsigned long mp3_frame_size(mp3_frame_t *frame) { return MP3_HDR_SIZE + frame->si_size + frame->adu_size + (frame->protected ? 0 : 2); } /*M **/ poc-0.4.2/ogg-write.c0000664000175000001440000000547110210123147015006 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include "pack.h" #include "file.h" #include "ogg.h" #include "crc32.h" int ogg_fill_page_hdr(ogg_page_t *page) { assert(page != NULL); unsigned long size = OGG_HDR_MIN_SIZE + page->page_segments; int i; for (i = 0; i < page->page_segments; i++) size += page->lacing_values[i]; if (page->raw.size < size) if (!buf_grow(&page->raw)) return 0; unsigned char *ptr = page->raw.data; UINT8_PACK(ptr, OGG_SYNC_HDR_BYTE1); UINT8_PACK(ptr, OGG_SYNC_HDR_BYTE2); UINT8_PACK(ptr, OGG_SYNC_HDR_BYTE3); UINT8_PACK(ptr, OGG_SYNC_HDR_BYTE4); UINT8_PACK(ptr, 0); unsigned char flags = 0; if (page->b.continuation) flags |= 1; if (page->b.first) flags |= 2; if (page->b.last) flags |= 4; UINT8_PACK(ptr, flags); memcpy(ptr, page->position, 8); ptr += 8; LE_UINT32_PACK(ptr, page->stream); LE_UINT32_PACK(ptr, page->page_no); LE_UINT32_PACK(ptr, 0); UINT8_PACK(ptr, page->page_segments); for (i = 0; i < page->page_segments; i++) UINT8_PACK(ptr, page->lacing_values[i]); return 1; } void ogg_fill_page_cksum(ogg_page_t *page) { assert(page != NULL); assert(page->raw.data != NULL); unsigned long cksum = crc32(&ogg_crc32, page->raw.data, page->size); unsigned char *ptr = page->raw.data + 22; LE_UINT32_PACK(ptr, cksum); } int ogg_write_page(file_t *ogg, ogg_page_t *page) { assert(ogg != NULL); assert(page != NULL); assert(page->raw.data != NULL); assert(page->size <= page->raw.size); if (file_write(ogg, page->raw.data, page->size) <= 0) return EEOF; return 1; } /*C **/ #ifdef OGG_WRITETEST #include #include int main(int argc, char *argv[]) { char *f[2]; if (!(f[0] = *++argv) || !(f[1] = *++argv)) { fprintf(stderr, "Usage: oggtest mp3in mp3out\n"); return 1; } file_t in; if (!file_open_read(&in, f[0])) { fprintf(stderr, "Could not open ogg file for read: %s\n", f[0]); return 1; } file_t out; if (!file_open_write(&out, f[1])) { fprintf(stderr, "Could not open ogg file for write: %s\n", f[1]); file_close(&in); return 1; } ogg_page_t page; ogg_init(); ogg_page_init(&page); while (ogg_next_page(&in, &page) > 0) { memset(page.raw.data, 0, OGG_HDR_MIN_SIZE); if (!ogg_fill_page_hdr(&page)) { ogg_page_destroy(&page); file_close(&in); file_close(&out); return 1; } ogg_fill_page_cksum(&page); if (ogg_write_page(&out, &page) <= 0) { fprintf(stderr, "Could not write page\n"); ogg_page_destroy(&page); file_close(&in); file_close(&out); return 1; } fgetc(stdin); } ogg_page_destroy(&page); file_close(&in); file_close(&out); return 0; } #endif /* OGG_WRITETEST */ poc-0.4.2/poc.rb0000664000175000001440000001342610204470566014060 0ustar manuelusers00000000000000require 'dl/import' module POC module FEC extend DL::Importable dlload "./libfec.so" # misc # FIXME: hier korrekter type und rausfinden # wie NULL Pointer in libfec_init uebergeben werden extern "void libfec_init(void *, void *) " extern "void libfec_close()" # IO extern "int libfec_read_adu(unsigned char *, unsigned int)" extern "void libfec_write_adu(unsigned char *, unsigned int)" # decoding extern "fec_decode_t *libfec_new_group(unsigned char, unsigned char, unsigned long)" extern "void libfec_add_pkt(fec_decode_t *, unsigned char, unsigned long, unsigned char*)" extern "unsigned int libfec_decode(fec_decode_t *, unsigned char *, unsigned int, unsigned int)" extern "void libfec_delete_group(fec_decode_t *)" #encoding extern "fec_encode_t *libfec_new_encode(unsigned char, unsigned char)" extern "int libfec_add_adu(fec_encode_t *, unsigned long, unsigned char *)" extern "unsigned int libfec_max_length(fec_encode_t *)" extern "unsigned int libfec_encode(fec_encode_t *, unsigned char *, unsigned int, unsigned int)" extern "void libfec_delete_encode(fec_encode_t *)" class Error < Exception end class Encoder def initialize(n, k) @group = FEC::libfec_new_encode(n, k) raise Error.new("cannot allocate new FEC group") unless @group if block_given? begin yield self ensure close end end end def add(data) success = FEC::libfec_add_adu(@group, data.size, data) == 1 raise Error.new("cannot add ADU to FEC group") unless success end def maxlen FEC::libfec_max_length(@group) end def encode(idx) bufferlen = maxlen buffer = (" " * bufferlen).to_ptr encoded = FEC::libfec_encode(@group, buffer, idx, bufferlen) buffer.to_s(encoded) end def close FEC::libfec_delete_encode(@group) end end class Decoder def initialize(n, k, len) @group = FEC::libfec_new_group(n, k, len) @maxlen = len raise Error.new("cannot allocate new FEC group") unless @group if block_given? begin yield self ensure close end end end def add(seq, data) FEC::libfec_add_pkt(@group, seq, data.size, data) end def decode(idx) buffer = (" " * @maxlen).to_ptr decoded = FEC::libfec_decode(@group, buffer, idx, @maxlen) return nil if decoded == 0 buffer.to_s(decoded) end def close FEC::libfec_delete_group(@group) end end def encode(pkts, k) raise Error.new("#pkts (#{pkts.size}) > k (#{k})") if pkts.size > k res = [] maxlen = 0 Encoder.new(pkts.size, k) do |encoder| pkts.each do |pkt| encoder.add(pkt) end k.times do |idx| res << encoder.encode(idx) end maxlen = encoder.maxlen end [maxlen, res] end # ... [pkt, nil, pkt, pkt, ...] def decode(pkts, n) maxlen = pkts.map{ |pkt| pkt ? pkt.size : 0 }.max res = [] Decoder.new(n, pkts.size, maxlen) do |decoder| pkts.each_with_index do |pkt, idx| next unless pkt decoder.add(idx, pkt) end n.times do |idx| res << decoder.decode(idx) end end res end module_function :decode, :encode def readAdu buffer = (" " * 4000).to_ptr len = FEC::libfec_read_adu(buffer, 4000) return nil if len == -1 buffer.to_s(len) end def writeAdu(adu) FEC::libfec_write_adu(adu, adu.size) end module_function :readAdu, :writeAdu def init(infile = nil, outfile = nil) libfec_init(infile, outfile) end module_function :init end end =begin POC::FEC::init("-", "-") while adu = POC::FEC::readAdu POC::FEC::writeAdu(adu) end =end if __FILE__ == $0 POC::FEC::init # 3 Datenpakete ... data = ["foooo", "bl0rg", "baaaz"] p data # ... aufblasen auf 5 (n = 3, k = 5) maxlen, encoded = POC::FEC::encode(data, 5) p encoded # Paket 1 und 2 gehen vorloren encoded[1] = nil encoded[2] = nil # die 3 original Pakete zurueckholen decoded = POC::FEC::decode(encoded, 3) p decoded end poc-0.4.2/fec-rb.h0000664000175000001440000000063410210123147014241 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef RTP_RB_H__ #define RTP_RB_H__ extern unsigned int fec_rb_cnt; extern unsigned int fec_rb_size; void fec_rb_clear(void); void fec_rb_destroy(void); void fec_rb_init(unsigned int size); unsigned int fec_rb_length(void); void fec_rb_pop(void); void fec_rb_print(void); int fec_rb_insert_pkt(fec_pkt_t *pkt, int idx); fec_group_t *fec_rb_first(void); #endif /* RTP_RB_H__ */ poc-0.4.2/fec.h0000664000175000001440000000126110210123147013635 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef FEC_H__ #define FEC_H__ #include "galois.h" /*M \emph{FEC parameter structure.} Contains the $n, k$ parameters for FEC, as well as the generator matrix. **/ typedef struct fec_s { /*M FEC parameters. **/ unsigned int k, n; /*M Linear block code generator matrix. **/ gf *gen_matrix; } fec_t; void fec_free(fec_t *fec); fec_t *fec_new(unsigned int k, unsigned int n); void fec_encode(fec_t *fec, gf *src[], gf *dst, unsigned int idx, unsigned int len); int fec_decode(fec_t *fec, gf *buf, unsigned int idxs[], unsigned len); /*C **/ #endif /* FEC_H__ */ poc-0.4.2/pogg-http.c0000664000175000001440000002016110214014115015002 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include #ifdef NEED_GETOPT_H__ #include #endif #include "file.h" #include "vorbis.h" #include "ogg.h" #include "network.h" #include "signal.h" #include "http.h" #include "misc.h" #ifdef WITH_IPV6 static int use_ipv6 = 0; #endif /* WITH_IPV6 */ static int finished = 0; /*M **/ #define OGG_BUF_LEN 65535 /* Maximal synchronization latency for sending packets in usecs. */ #define MAX_WAIT_TIME (1 * 1000) #define MAX_FILENAME 256 static void sig_int(int signo) { finished = 1; } int ogg_callback(http_client_t *client, void *data) { vorbis_stream_t *vorbis = data; /* XXX write ogg headers */ int i; for (i = 0; i < vorbis->hdr_pages_cnt; i++) { if (!unix_write(client->fd, vorbis->hdr_pages[i].raw.data, vorbis->hdr_pages[i].size) != vorbis->hdr_pages[i].size) return -1; } return 0; } /*M \emph{Simple HTTP streaming server main loop.} The mainloop opens the Vorbis OGG file \verb|filename|, reads each audio packet and sends it out using HTTP. After sending a packet, the mainloop sleeps for the duration of the packet, synchronizing itself when the sleep is not accurate enough. If the sleep desynchronizes itself from the stream more than \verb|MAX_WAIT_TIME|, the synchronization is reset. **/ int pogg_mainloop(http_server_t *server, char *filename, int quiet) { /*M Open file for reading. **/ vorbis_stream_t vorbis; vorbis_stream_init(&vorbis); if (!file_open_read(&vorbis.file, filename) || !vorbis_stream_read_hdrs(&vorbis)) { fprintf(stderr, "Could not open ogg file: %s\n", filename); vorbis_stream_destroy(&vorbis); return 0; } if (!quiet) fprintf(stderr, "\rStreaming %s...\n", filename); static long wait_time = 0; unsigned long page_time = 0, last_time = 0; ogg_page_t page; ogg_page_init(&page); /*M Cycle through the frames and send them using HTTP. **/ while ((ogg_next_page(&vorbis.file, &page) >= 0) && !finished) { /*M Get start time for this page iteration. **/ struct timeval tv; gettimeofday(&tv, NULL); unsigned long start_sec, start_usec; start_sec = tv.tv_sec; start_usec = tv.tv_usec; /*M Go through HTTP main routine and check for timeouts, received data, etc... **/ if (!http_server_main(server, &vorbis)) { fprintf(stderr, "Http main error\n"); file_close(&vorbis.file); vorbis_stream_destroy(&vorbis); ogg_page_destroy(&page); return 0; } /*M Write frame to HTTP clients. **/ int i; for (i = 0; i < server->num_clients; i++) { if ((server->clients[i].fd != -1) && (server->clients[i].found >= 2)) { int ret; ret = unix_write(server->clients[i].fd, page.raw.data, page.size); if (ret != page.size) { fprintf(stderr, "Error writing to client %d\n", i); http_client_close(server, server->clients + i); } } } last_time = page_time; page_time = ogg_position_to_msecs(&page, vorbis.audio_sample_rate); wait_time += page_time - last_time; /*M Sleep for duration of frame. **/ if (wait_time > 200) usleep((wait_time) * 1000); /*M Print information. **/ if (!quiet) { static int count = 0; if ((count++ % 10) == 0) { if (vorbis.file.size > 0) { fprintf(stderr, "\r%02ld:%02ld/%02ld:%02ld %7ld/%7ld " "(%3ld%%) %3ldkbit/s %4ldb ", (page_time/1000) / 60, (page_time/1000) % 60, (long)((float)(page_time) / ((float)vorbis.file.offset+1) * (float)vorbis.file.size) / 60000, (long)((float)(page_time) / ((float)vorbis.file.offset+1) * (float)vorbis.file.size) / 1000 % 60, vorbis.file.offset, vorbis.file.size, (long)(100*(float)vorbis.file.offset/(float)vorbis.file.size), vorbis.bitrate_nominal/1000, page.size); } else { fprintf(stderr, "\r%02ld:%02ld %ld %3ldkbit/s %4ldb ", (page_time/1000) / 60, (page_time/1000) % 60, vorbis.file.offset, vorbis.bitrate_nominal/1000, page.size); } } fflush(stderr); } /*M Get length of iteration. **/ gettimeofday(&tv, NULL); unsigned long len = (tv.tv_sec - start_sec) * 1000 + (tv.tv_usec - start_usec) / 1000; wait_time -= len; if (abs(wait_time) > MAX_WAIT_TIME) wait_time = 0; } if (!file_close(&vorbis.file)) { fprintf(stderr, "Could not close ogg file %s\n", filename); vorbis_stream_destroy(&vorbis); ogg_page_destroy(&page); return 0; } vorbis_stream_destroy(&vorbis); ogg_page_destroy(&page); return 1; } /*M \emph{Print usage information.} **/ static void usage(void) { fprintf(stderr, "Usage: ./pogg-http [-s address] [-p port] [-q] [-c clients]"); #ifdef WITH_IPV6 fprintf(stderr, " [-6]"); #endif fprintf(stderr, " files...\n"); fprintf(stderr, "\t-s address : source address (default 0.0.0.0)\n"); fprintf(stderr, "\t-p port : port to listen on (default 8000)\n"); fprintf(stderr, "\t-q : quiet\n"); fprintf(stderr, "\t-c clients : maximal number of clients (default 0, illimited)\n"); #ifdef WITH_IPV6 fprintf(stderr, "\t-6 : use ipv6\n"); #endif } /*M \emph{HTTP server main routine.} **/ int main(int argc, char *argv[]) { int retval = 0; char *address = NULL; unsigned short port = 8000; int quiet = 0; int max_clients = 0; http_server_t server; http_server_reset(&server); if (argc <= 1) { usage(); return 1; } int c; while ((c = getopt(argc, argv, "hs:p:qc:" #ifdef WITH_IPV6 "6" #endif /* WITH_IPV6 */ )) >= 0) { switch (c) { #ifdef WITH_IPV6 case '6': use_ipv6 = 1; break; #endif /* WITH_IPV6 */ case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = (unsigned short)atoi(optarg); break; case 'c': max_clients = (unsigned short)atoi(optarg); break; case 'q': quiet = 1; break; case 'h': default: usage(); retval = EXIT_FAILURE; goto exit; } } if (optind == argc) { usage(); retval = EXIT_FAILURE; goto exit; } if (address == NULL) { #ifdef WITH_IPV6 if (use_ipv6) address = strdup("0::0"); else address = strdup("0"); #else address = strdup("0"); #endif /* WITH_IPV6 */ } if (sig_set_handler(SIGINT, sig_int) == SIG_ERR) { retval = EXIT_FAILURE; goto exit; } ogg_init(); /*M Open the listening socket. **/ int sock = -1; #ifdef WITH_IPV6 if (use_ipv6) sock = net_tcp6_listen_socket(address, port); else sock = net_tcp4_listen_socket(address, port); #else sock = net_tcp4_listen_socket(address, port); #endif /* WITH_IPV6 */ if (sock < 0) { perror("Could not create socket"); retval = EXIT_FAILURE; goto exit; } if (!http_server_init(&server, HTTP_MIN_CLIENTS, max_clients, ogg_callback, sock)) { fprintf(stderr, "Could not initialise HTTP server\n"); retval = EXIT_FAILURE; goto exit; } /*M Read in ogg files one after the other. **/ int i; for (i=optind; (iraw + 4 + ((f)->protected ? 0 : 2) + (f)->si_size) #include "file.h" int mp3_read_si(mp3_frame_t *frame); int mp3_read_hdr(mp3_frame_t *frame); int mp3_read_sf(mp3_frame_t *frame); int mp3_next_frame(file_t *mp3, mp3_frame_t *frame); int mp3_unpack(mp3_frame_t *frame); int mp3_fill_si(mp3_frame_t *frame); int mp3_fill_hdr(mp3_frame_t *frame); int mp3_write_frame(file_t *file, mp3_frame_t *frame); int mp3_trans_frame(mp3_frame_t *frame); void mp3_calc_hdr(mp3_frame_t *frame); unsigned long mp3_frame_size(mp3_frame_t *frame); /*M **/ #endif /* MP3_H__ */ poc-0.4.2/rtp-rb.c0000664000175000001440000000607310210123147014307 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include "rtp.h" /*M \emph{Maximal number of elements in the ring buffer.} **/ unsigned int rtp_rb_size = 0; /*M \emph{Index of first valid element in ring buffer.} **/ static unsigned int rtp_rb_start = 0; /*M \emph{Index of first invalid element in ring buffer.} **/ static unsigned int rtp_rb_end = 0; /*M \emph{Number of elements in the ring buffer.} **/ unsigned int rtp_rb_cnt = 0; /*M \emph{Ring buffer array.} **/ rtp_pkt_t *rtp_rb = NULL; void rtp_rb_clear(void) { rtp_rb_start = 0; rtp_rb_end = 0; rtp_rb_cnt = 0; int i; for (i = 0; i < rtp_rb_size; i++) { rtp_pkt_init(rtp_rb + i); rtp_rb[i].length = 0; } } void rtp_rb_destroy(void) { if (rtp_rb != NULL) { free(rtp_rb); rtp_rb = NULL; } rtp_rb_size = 0; rtp_rb_clear(); } void rtp_rb_init(unsigned int size) { rtp_rb_destroy(); rtp_rb = malloc(sizeof(rtp_pkt_t) * size); assert(rtp_rb != NULL); rtp_rb_size = size; rtp_rb_clear(); } unsigned int rtp_rb_length(void) { assert(rtp_rb != NULL); if (rtp_rb_end >= rtp_rb_start) return rtp_rb_end - rtp_rb_start; else return rtp_rb_end + (rtp_rb_size - rtp_rb_start); } void rtp_rb_pop(void) { assert(rtp_rb != NULL); assert(rtp_rb_end != rtp_rb_start); rtp_rb[rtp_rb_start].length = 0; rtp_rb_start = (rtp_rb_start + 1) % rtp_rb_size; rtp_rb_cnt--; } int rtp_rb_insert_pkt(rtp_pkt_t *pkt, int idx) { assert(pkt != NULL); assert(rtp_rb != NULL); #ifdef DEBUG fprintf(stderr, "insert packet at idx %d\n", idx); #endif if (idx < 0) { /* try to grow the buffer downwards */ if ((rtp_rb_length() - idx) <= rtp_rb_size) { rtp_rb_start = (rtp_rb_start + idx) % rtp_rb_size; idx = 0; } else /* drop the packet silently */ return 0; } else if (idx >= rtp_rb_size - 1) { /* not enough place left in ring buffer */ return 0; } rtp_pkt_t *dstpkt = rtp_rb + ((idx + rtp_rb_start) % rtp_rb_size); assert(dstpkt->length == 0); memcpy(dstpkt, pkt, sizeof(rtp_pkt_t)); rtp_rb_cnt++; #ifdef DEBUG fprintf(stderr, "packet inserted at %d, end: %d\n", (idx + rtp_rb_start) % rtp_rb_size, rtp_rb_end); #endif /* adjust the end pointer */ if (idx >= rtp_rb_length()) rtp_rb_end = ((idx + rtp_rb_start + 1)% rtp_rb_size); assert(rtp_rb_start != rtp_rb_end); assert(rtp_rb[rtp_rb_end].length == 0); return 1; } void rtp_rb_print(void) { assert(rtp_rb != NULL); fprintf(stderr, "start: %.3u, end: %.3u, len: %.3u\n", rtp_rb_start, rtp_rb_end, rtp_rb_length()); } void rtp_rb_print_rb(void) { unsigned int i; for (i = rtp_rb_start; i != rtp_rb_end; i = (i + 1) % rtp_rb_size) { if (rtp_rb[i].length != 0) fprintf(stderr, "%.3u: seq %.3u\n", i, rtp_rb[i].b.seq); } } rtp_pkt_t *rtp_rb_first(void) { assert(rtp_rb != NULL); if (rtp_rb_start == rtp_rb_end) return NULL; /* first should always be the first in buffer */ return rtp_rb + rtp_rb_start; } poc-0.4.2/rtp.c0000664000175000001440000002712110214014115013701 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #ifdef WITH_OPENSSL #include #include #endif #ifdef DEBUG #include #endif #include "pack.h" #include "rtp.h" #include "misc.h" /*@+charint@*/ /*@+boolint@*/ /*M \emph{Initialize a RTP packet by filling common header fields.} Synchronization source and sequence number are filled using random numbers, payload length is set to 0. **/ void rtp_pkt_init(rtp_pkt_t *pkt) { assert(pkt != NULL); /*M RTP version 2. **/ pkt->b.v = 2; /*M We use no padding (at first). **/ pkt->b.p = 0; /*M No extensions (at first). **/ pkt->b.x = 0; /*M No csrc identifiers at first. **/ pkt->b.cc = 0; /*M Set the sequence number to 0. **/ pkt->b.seq = 0; /*M Generate a random synchronization source. **/ pkt->ssrc = ((unsigned int)rand()) & 0xFFFFFFFF; /*M The payload length is $0$ at first. **/ pkt->length = 0; /*M The padding length is $0$ at first. **/ pkt->plen = 0; pkt->hlen = RTP_HDR_SIZE; pkt->payload = pkt->data + pkt->hlen; pkt->pack = NULL; pkt->unpack = NULL; } /*M \emph{Fill the packet data by packing the header information.} **/ void rtp_pkt_pack(rtp_pkt_t *pkt) { assert(pkt != NULL); /* v: 2 bits, p: 1 bit, x: 1 bit, cc: 4 bits */ pkt->data[0] = (pkt->b.v & 0x3) << 6; pkt->data[0] |= (pkt->b.p & 0x1) << 5; pkt->data[0] |= (pkt->b.x & 0x1) << 4; pkt->data[0] |= (pkt->b.cc & 0xf); /* m: 1 bit, pt: 7 bits */ pkt->data[1] = (pkt->b.m & 0x1) << 7; pkt->data[1] |= (pkt->b.pt & 0x7f); unsigned char *ptr = pkt->data + 2; /* seq: 16 bits */ UINT16_PACK(ptr, pkt->b.seq); /* timestamp: 32 bits */ UINT32_PACK(ptr, pkt->timestamp); /* ssrc: 32 bits */ UINT32_PACK(ptr, pkt->ssrc); if (pkt->pack) pkt->pack(pkt); /*M If we use padding, add padding length at the end of the payload. **/ if (pkt->b.p) { assert((pkt->length + pkt->hlen + pkt->b.cc * RTP_CSRC_SIZE + pkt->plen + 1) < RTP_PKT_SIZE); unsigned char *ptr = pkt->data + pkt->hlen + pkt->length + pkt->plen; *ptr = pkt->plen; } } /*M \emph{Send a RTP packet to filedescriptor using send.} Fills the packet data buffer with the packed header, increments the sequence number and sends it out. **/ ssize_t rtp_pkt_send(rtp_pkt_t *pkt, int fd) { assert(pkt != NULL); rtp_pkt_pack(pkt); /*M Increment sequence number. **/ pkt->b.seq++; unsigned int len = pkt->length + pkt->hlen + pkt->b.cc * RTP_CSRC_SIZE; /*M If padding is 1, then we have signed the packet. **/ if (pkt->b.p) len += pkt->plen + 1; /*M Send pack on \verb|fd|. **/ return send(fd, pkt->data, len, 0); } /*M \emph{Read a RTP packet from filedescriptor.} Reads a RTP packet from the filedescriptor, and unpacks the RTP header into the \verb|rtp_pkt_t| data fields. **/ int rtp_pkt_read(rtp_pkt_t *pkt, int fd) { assert(pkt != NULL); ssize_t len; switch (len = unix_read(fd, pkt->data, RTP_PKT_SIZE)) { case 0: /* EOF */ return 0; case -1: /* error */ return -1; default: break; } /*M Check if the packet is long enough. **/ if (len < RTP_HDR_SIZE) return -1; pkt->length = len; return rtp_pkt_unpack(pkt); } /*M \emph{Fill the RTP packet structure by unpacking payload information.} **/ int rtp_pkt_unpack(rtp_pkt_t *pkt) { assert(pkt != NULL); /* v: 2 bits, p: 1 bit, x: 1 bit, cc: 4 bits */ pkt->b.v = (pkt->data[0] >> 6) & 0x3; /* check version */ if (pkt->b.v != 2) return 0; pkt->b.p = (pkt->data[0] >> 5) & 0x1; pkt->b.x = (pkt->data[0] >> 4) & 0x1; pkt->b.cc = (pkt->data[0]) & 0xf; /* m: 1 bit, pt: 7 bits */ pkt->b.m = (pkt->data[1] >> 7) & 0x1; pkt->b.pt = (pkt->data[1]) & 0x7f; unsigned char *ptr = pkt->data + 2; /* seq: 16 bits */ pkt->b.seq = UINT16_UNPACK(ptr); /* timestamp: 32 bits */ pkt->timestamp = UINT32_UNPACK(ptr); /* ssrc: 32 bits, just ignore it */ ptr += 4; if (pkt->unpack) if (!pkt->unpack(pkt)) return 0; /*M If padding is used, then padding length is in last byte. **/ if (pkt->b.p) { unsigned char *plen = pkt->data + pkt->length - 1; pkt->plen = *plen; } else { pkt->plen = 0; } /*M Ignore rest of packet for now. **/ pkt->length -= pkt->hlen + pkt->b.cc * RTP_CSRC_SIZE; if (pkt->b.p) pkt->length -= pkt->plen + 1; return 1; } /*M \emph{Sign a packet using RSA.} First compute a SHA1 hash of the packet payload, and sign it using the RSA private key in \verb|rsa|. **/ #ifdef WITH_OPENSSL int rtp_pkt_sign(rtp_pkt_t *pkt, RSA *rsa) { assert(pkt != NULL); assert(rsa != NULL); if (pkt->length + RSA_size(rsa) + 1 > RTP_PKT_SIZE) return 0; EVP_MD_CTX ctx; EVP_DigestInit(&ctx, EVP_sha1()); EVP_DigestUpdate(&ctx, pkt->data + pkt->hlen, pkt->length); unsigned char md[EVP_MAX_MD_SIZE]; unsigned int mdlen; EVP_DigestFinal(&ctx, md, &mdlen); int slen; if (!RSA_sign(NID_sha1, md, mdlen, pkt->data + pkt->hlen + pkt->length, &slen, rsa)) return 0; pkt->plen = slen; pkt->b.p = 1; return 1; } /*M \emph{Verify a packet using RSA.} First compute a SHA1 hash of the packet payload, and verify it against the signed hash value in the padding using the public key in \verb|rsa|. **/ int rtp_pkt_verify(rtp_pkt_t *pkt, RSA *rsa) { assert(pkt != NULL); assert(rsa != NULL); if (pkt->plen != RSA_size(rsa)) return 0; EVP_MD_CTX ctx; EVP_DigestInit(&ctx, EVP_sha1()); EVP_DigestUpdate(&ctx, pkt->data + pkt->hlen, pkt->length); unsigned char md[EVP_MAX_MD_SIZE]; unsigned int mdlen; EVP_DigestFinal(&ctx, md, &mdlen); if (!RSA_verify(NID_sha1, md, mdlen, pkt->data + pkt->hlen + pkt->length, pkt->plen, rsa)) return 0; return 1; } #endif /* WITH_OPENSSL */ /*M \emph{Fill the packet data by packing the header information.} Fills the MPEG header with 0s. **/ void rtp_rfc2250_pkt_pack(rtp_pkt_t *pkt) { assert(pkt != NULL); unsigned char *ptr = pkt->data + RTP_HDR_SIZE; UINT32_PACK(ptr, 0x00000000); } /*M \emph{Unpack a RTP RFC2250 packet.} **/ int rtp_rfc2250_pkt_unpack(rtp_pkt_t *pkt) { if ((pkt->b.pt != RTP_PT_SMPA) && (pkt->b.pt != RTP_PT_MPA)) return 0; return 1; } /*M \emph{Initialize a RFC2250 RTP packet by filling common header fields.} **/ void rtp_rfc2250_pkt_init(rtp_pkt_t *pkt) { rtp_pkt_init(pkt); pkt->hlen += RTP_RFC2250_HDR_SIZE; pkt->pack = rtp_rfc2250_pkt_pack; pkt->unpack = rtp_rfc2250_pkt_unpack; } /*M \emph{Fill the packet data by packing the header information.} **/ void rtp_rfc3119_pkt_pack(rtp_pkt_t *pkt) { assert(pkt != NULL); unsigned char *ptr = pkt->data + RTP_HDR_SIZE; if (pkt->length > ((1 << 6) - 1)) pkt->rfc3119_b.t = 1; else pkt->rfc3119_b.t = 0; if (pkt->rfc3119_b.t) { /* 14 bits length */ *ptr = pkt->rfc3119_b.c << 7; *ptr |= 1 << 6; *ptr |= ((pkt->length >> 8) & 0x3f); ptr++; pkt->length++; *ptr = (pkt->length & 0xFF); } else { /* 6 bits length */ *ptr = 0; *ptr = (pkt->length & 0x3f); *ptr |= pkt->rfc3119_b.c << 7; } } /*M \emph{Unpack a RTP RFC3119 packet.} **/ int rtp_rfc3119_pkt_unpack(rtp_pkt_t *pkt) { if (pkt->b.pt != RTP_DYN) return 0; unsigned char *ptr = pkt->data + pkt->hlen - 1; pkt->rfc3119_b.c = (*ptr >> 7) & 1; assert((pkt->rfc3119_b.c == 0) || "Continuation is not handled yet"); pkt->rfc3119_b.t = (*ptr >> 6) & 1; unsigned short length; if (pkt->rfc3119_b.t) { length = (*(ptr++) & 0x3F) << 8; length |= (*ptr & 0xFF); pkt->length--; } else { length = (*ptr & 0x3F); } assert((pkt->length == length) || "error while decoding RFC3119 length"); return 1; } /*M \emph{Initialize a RFC3119 RTP packet by filling common header fields.} **/ void rtp_rfc3119_pkt_init(rtp_pkt_t *pkt) { rtp_pkt_init(pkt); pkt->rfc3119_b.c = 0; pkt->rfc3119_b.t = 0; pkt->b.pt = RTP_DYN; pkt->hlen += 1; /* short rfc3119 header version */ pkt->pack = rtp_rfc3119_pkt_pack; pkt->unpack = rtp_rfc3119_pkt_unpack; } /*C **/ #ifdef RTP_TEST #include static void testit(char *name, unsigned long result, unsigned long should) { if (result == should) { printf("Test %s was successful\n", name); } else { printf("Test %s was not successful, %lx should have been %lx\n", name, result, should); } } int main(void) { rtp_pkt_t pkt1, pkt2; int retval = 0; rtp_pkt_init(&pkt1); rtp_pkt_init(&pkt2); pkt1.b.cc = 0; pkt1.b.m = 1; pkt1.b.m = 0xF; rtp_pkt_pack(&pkt1); memcpy(pkt2.data, pkt1.data, RTP_PKT_SIZE); pkt2.length = pkt1.length + RTP_HDR_SIZE; if (!rtp_pkt_unpack(&pkt2)) { fprintf(stderr, "Could not unpack packet\n"); retval = 1; goto finished; } testit("pack unpack test 1", pkt2.b.v, pkt1.b.v); testit("pack unpack test 2", pkt2.b.p, pkt1.b.p); testit("pack unpack test 3", pkt2.b.x, pkt1.b.x); testit("pack unpack test 4", pkt2.b.cc, pkt1.b.cc); testit("pack unpack test 5", pkt2.b.m, pkt1.b.m); testit("pack unpack test 6", pkt2.b.pt, pkt1.b.pt); testit("pack unpack test 7", pkt2.b.seq, pkt1.b.seq); testit("pack unpack test 8", pkt2.timestamp, pkt1.timestamp); testit("pack unpack test 9", pkt2.b.seq, pkt1.b.seq); testit("pack unpack test 10", pkt2.plen, pkt1.plen); testit("pack unpack test 11", pkt2.length, pkt1.length); pkt1.b.p = 1; pkt1.plen = 10; rtp_pkt_pack(&pkt1); memcpy(pkt2.data, pkt1.data, RTP_PKT_SIZE); pkt2.length = pkt1.length + pkt1.plen + 1 + RTP_HDR_SIZE; if (!rtp_pkt_unpack(&pkt2)) { fprintf(stderr, "Could not unpack packet\n"); retval = 1; goto finished; } testit("pack unpack test 1", pkt2.b.v, pkt1.b.v); testit("pack unpack test 2", pkt2.b.p, pkt1.b.p); testit("pack unpack test 3", pkt2.b.x, pkt1.b.x); testit("pack unpack test 4", pkt2.b.cc, pkt1.b.cc); testit("pack unpack test 5", pkt2.b.m, pkt1.b.m); testit("pack unpack test 6", pkt2.b.pt, pkt1.b.pt); testit("pack unpack test 7", pkt2.b.seq, pkt1.b.seq); testit("pack unpack test 8", pkt2.timestamp, pkt1.timestamp); testit("pack unpack test 9", pkt2.b.seq, pkt1.b.seq); testit("pack unpack test 10", pkt2.plen, pkt1.plen); testit("pack unpack test 11", pkt2.length, pkt1.length); rtp_rfc3119_pkt_init(&pkt1); rtp_rfc3119_pkt_init(&pkt2); pkt1.length = 0x337; rtp_rfc3119_pkt_pack(&pkt1); memcpy(pkt2.data, pkt1.data, RTP_PKT_SIZE); pkt2.length = pkt1.length + RTP_HDR_SIZE + 1 + pkt1.rfc3119_b.t; if (!rtp_rfc3119_pkt_unpack(&pkt2)) { fprintf(stderr, "Could not unpack packet\n"); retval = 1; goto finished; } testit("pack unpack test 1", pkt2.b.v, pkt1.b.v); testit("pack unpack test 2", pkt2.b.p, pkt1.b.p); testit("pack unpack test 3", pkt2.b.x, pkt1.b.x); testit("pack unpack test 4", pkt2.b.cc, pkt1.b.cc); testit("pack unpack test 5", pkt2.b.m, pkt1.b.m); testit("pack unpack test 6", pkt2.b.pt, pkt1.b.pt); testit("pack unpack test 7", pkt2.b.seq, pkt1.b.seq); testit("pack unpack test 8", pkt2.timestamp, pkt1.timestamp); testit("pack unpack test 9", pkt2.b.seq, pkt1.b.seq); testit("pack unpack test 10", pkt2.plen, pkt1.plen); testit("pack unpack test 11", pkt2.length, pkt1.length); testit("pack unpack test 10", pkt2.rfc3119_b.c, pkt1.rfc3119_b.c); testit("pack unpack test 11", pkt2.rfc3119_b.t, pkt1.rfc3119_b.t); finished: return retval; } #endif /* RTP_TEST */ poc-0.4.2/ogg-read.c0000664000175000001440000001332010210123147014557 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include "file.h" #include "pack.h" #include "ogg.h" #include "crc32.h" #ifdef DEBUG void ogg_print_page_hdr(ogg_page_t *page) { assert(page != NULL); fprintf(stderr, "page (size: %lu)\n", page->size); fprintf(stderr, "flags: c:%d, f:%d, l:%d\n", page->b.continuation, page->b.first, page->b.last); fprintf(stderr, "stream: %lx, page_no: %lx\n", page->stream, page->page_no); fprintf(stderr, "position: %x%x %x%x %x%x %x%x\n", page->position[0], page->position[1], page->position[2], page->position[3], page->position[4], page->position[5], page->position[6], page->position[7]); fprintf(stderr, "cksum: %lx, page_segments: %d\n", page->page_cksum, page->page_segments); } void ogg_print_page_segment_table(ogg_page_t *page) { assert(page != NULL); int i; for (i = 0; i < page->page_segments; i++) { fprintf(stderr, "segment %d, lacing value: %d\n", i, page->lacing_values[i]); } } #endif /* DEBUG */ int ogg_unpack_page_hdr(ogg_page_t *page) { assert(page != NULL); assert(page->size >= OGG_HDR_MIN_SIZE); unsigned char *ptr = page->raw.data + 4; if (*ptr++ != 0) return 0; page->b.continuation = (*ptr & 1) ? 1 : 0; page->b.first = (*ptr & 2) ? 1 : 0; page->b.last = (*ptr & 4) ? 1 : 0; ptr++; memcpy(page->position, ptr, 8); ptr += 8; page->stream = LE_UINT32_UNPACK(ptr); page->page_no = LE_UINT32_UNPACK(ptr); page->page_cksum = LE_UINT32_UNPACK(ptr); page->page_segments = UINT8_UNPACK(ptr); return 1; } void ogg_unpack_page_segment_table(ogg_page_t *page) { assert(page != NULL); assert(page->size >= (OGG_HDR_MIN_SIZE + page->page_segments)); unsigned char *ptr = page->raw.data + OGG_HDR_MIN_SIZE; int i; for (i = 0; i < page->page_segments; i++) page->lacing_values[i] = UINT8_UNPACK(ptr); } int ogg_check_page_cksum(ogg_page_t *page) { assert(page != NULL); assert(page->size >= OGG_HDR_MIN_SIZE); /*M Fill the checksum in the raw frame with 0 bytes. **/ unsigned char *ptr = page->raw.data + 22; memset(ptr, 0, 4); /*M Check the CRC32 sum of the whole page. **/ unsigned long crc = crc32(&ogg_crc32, page->raw.data, page->size); LE_UINT32_PACK(ptr, page->page_cksum); if (crc == page->page_cksum) return 1; else return 0; } /*M \emph{Read next OGG page from the OGG file.} **/ int ogg_next_page(file_t *ogg, ogg_page_t *page) { assert(ogg != NULL); assert(page != NULL); page->size = 0; if (page->raw.size < OGG_HDR_MIN_SIZE) { if (!buf_grow(&page->raw)) return 0; } page->raw.len = 0; /*M Try to sync on OGG stream. **/ unsigned int resync = 0; again: if (resync != 0) { /*M Read the next byte and try to sync on the new header. **/ if (file_read(ogg, page->raw.data + 3, 1) <= 0) return EEOF; } else { if (file_read(ogg, page->raw.data, OGG_SYNC_HDR_SIZE) <= 0) return EEOF; } /*M Check if the header magic bytes are correct. **/ if ((page->raw.data[0] != OGG_SYNC_HDR_BYTE1) || (page->raw.data[1] != OGG_SYNC_HDR_BYTE2) || (page->raw.data[2] != OGG_SYNC_HDR_BYTE3) || (page->raw.data[3] != OGG_SYNC_HDR_BYTE4)) { if (resync++ > OGG_MAX_SYNC) { fprintf(stderr, "Max sync exceeded: %d\n", resync); return ESYNC; } else goto again; } else { resync = 0; } page->size = OGG_SYNC_HDR_SIZE; page->raw.len = OGG_SYNC_HDR_SIZE; /*M Read rest of header. **/ if (file_read(ogg, page->raw.data + OGG_SYNC_HDR_SIZE, OGG_HDR_MIN_SIZE - OGG_SYNC_HDR_SIZE) <= 0) return EEOF; page->size = OGG_HDR_MIN_SIZE; page->raw.len = OGG_HDR_MIN_SIZE; if (!ogg_unpack_page_hdr(page)) { fprintf(stderr, "Could not unpack the OGG page header\n"); return 0; } #ifdef DEBUG ogg_print_page_hdr(page); #endif /* DEBUG */ /*M Read segment table. **/ if (page->raw.size < (OGG_HDR_MIN_SIZE + page->page_segments)) { if (!buf_grow(&page->raw)) return 0; } if (page->page_segments > 0) { if (file_read(ogg, page->raw.data + OGG_HDR_MIN_SIZE, page->page_segments) <= 0) return EEOF; page->size += page->page_segments; page->raw.len += page->page_segments; ogg_unpack_page_segment_table(page); #ifdef DEBUG ogg_print_page_segment_table(page); #endif /* DEBUG */ /*M Read segments. **/ int i; for (i = 0; i < page->page_segments; i++) { if (page->lacing_values[i] > 0) { if ((page->raw.size - page->size) <= page->lacing_values[i]) { if (!buf_grow(&page->raw)) return 0; } if (file_read(ogg, page->raw.data + page->size, page->lacing_values[i]) <= 0) return EEOF; page->size += page->lacing_values[i]; page->raw.len += page->lacing_values[i]; } } } ogg_check_page_cksum(page); return 1; } #ifdef OGG_TEST int main(int argc, char *argv[]) { file_t file; ogg_page_t page; ogg_init(); ogg_page_init(&page); char *f; if (!(f = *++argv)) { fprintf(stderr, "Usage: oggtest oggfile\n"); return 1; } if (!file_open_read(&file, f)) { fprintf(stderr, "Could not open ogg file: %s\n", f); return 1; } unsigned long last_msecs = 0; while (ogg_next_page(&file, &page) > 0) { unsigned long msecs = ogg_position_to_msecs(&page, 44100); fprintf(stderr, "msecs: %lu\n", msecs - last_msecs); last_msecs = msecs; fgetc(stdin); } ogg_page_destroy(&page); file_close(&file); return 0; } #endif /* OGG_TEST */ /*C **/ poc-0.4.2/rtp-rb.h0000664000175000001440000000063210210123147014307 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef RTP_RB_H__ #define RTP_RB_H__ extern unsigned int rtp_rb_cnt; extern unsigned int rtp_rb_size; void rtp_rb_clear(void); void rtp_rb_destroy(void); void rtp_rb_init(unsigned int size); unsigned int rtp_rb_length(void); void rtp_rb_pop(void); void rtp_rb_print(void); int rtp_rb_insert_pkt(rtp_pkt_t *pkt, int idx); rtp_pkt_t *rtp_rb_first(void); #endif /* RTP_RB_H__ */ poc-0.4.2/rtp.h0000664000175000001440000001267310210123147013716 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef RTP_H__ #define RTP_H__ #include /*@-exportlocal@*/ /*M \emph{Structure representing the 32 first bits of a RTP packet header.} **/ typedef struct rtp_bits_s { unsigned int v :2; /* version */ unsigned int p :1; /* padding */ unsigned int x :1; /* number of extension headers */ unsigned int cc :4; /* number of CSRC identifiers */ unsigned int m :1; /* marker */ unsigned int pt :7; /* payload type */ unsigned int seq :16; /* sequence number */ } rtp_bits_t; /*M \emph{Structure representing the flags of a RFC3119 packet.} **/ typedef struct rtp_rfc3119_bits_s { unsigned int c :1; /* continuation flag */ unsigned int t :1; /* descriptor type flag */ } rtp_rfc3119_bits_t; /*M \emph{Structure representing the flags of a Vorbis RTP packet.} **/ typedef struct rtp_vorbis_bits_s { unsigned int c :1; /* continuation flag */ unsigned int r1 :1; /* reserved bit 1 */ unsigned int r2 :1; /* reserved bit 2 */ /*M Number of complete packets in the payload. If C is set to 1, this should be 0. */ unsigned int pkt_num :5; } rtp_vorbis_bits_t; /*M \emph{Default RTP packet size.} **/ #define RTP_PKT_SIZE 1500 /*C \emph{RTP header structure.} \verbatim{ 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |V=2|P|X| CC |M| PT | sequence number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | synchronization source (SSRC) identifier | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | contributing source (CSRC) identifiers | | .... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } **/ /*M \emph{Structure representing a RTP packet.} The \verb|data| buffer is not the payload buffer, it contains the complete data for the packet. Be careful to update the payload pointer correctly when adding additional headers. **/ typedef struct rtp_pkt_s { /* first 32 bits */ rtp_bits_t b; unsigned long timestamp; /* synchronization source */ unsigned long ssrc; /* padding length */ unsigned char plen; /* header length */ unsigned int hlen; /* payload data length */ size_t length; /* packet data */ unsigned char data[RTP_PKT_SIZE]; /* pointer to payload inside the packet data */ unsigned char *payload; /* pointer to pack and unpack routine */ void (*pack)(struct rtp_pkt_s *); int (*unpack)(struct rtp_pkt_s *); /* rfc3119 header */ rtp_rfc3119_bits_t rfc3119_b; /* vorbis header */ rtp_vorbis_bits_t vorbis_b; } rtp_pkt_t; /*M \emph{RTP header size.} **/ #define RTP_HDR_SIZE 12 /*M \emph{RTP CSRC list entry size.} **/ #define RTP_CSRC_SIZE 4 void rtp_pkt_init(/*@out@*/ rtp_pkt_t *pkt); void rtp_pkt_pack(rtp_pkt_t *pkt); ssize_t rtp_pkt_send(rtp_pkt_t *pkt, int fd); int rtp_pkt_unpack(rtp_pkt_t *pkt); int rtp_pkt_read(rtp_pkt_t *pkt, int fd); #ifdef WITH_OPENSSL #include int rtp_pkt_sign(rtp_pkt_t *pkt, RSA *rsa); int rtp_pkt_verify(rtp_pkt_t *pkt, RSA *rsa); #endif /* WITH_OPENSSL */ /*C \emph{RTP RFC2250 packet header.} 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | MBZ (unused bits) | Fragmentation offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ **/ /*M \emph{RTP RFC2250 packet structure.} (RFC2250) The RTP header fields are used as follows: \begin{description} \item[Payload Type]: Distinct payload types should be assigned for MPEG1 Systems Streams, MPEG2 Program Streams and MPEG2 Transport Streams. \item[M bit]: Set to 1 whenever the timestamp is discontinuous (such as might happen when a sender switches from one data source to another). This allows the received and any intervening RTP mixers or transators that are synchronizing to the flow to ignore the difference between this timestamp and any previous timestamp in their clock phase detectors. \item[timestamp]: 32 bit 90 KHz timestamp representing the target transmission time for the first byte of the packet. \end{description} A distinct RTP payload type is assigned to MPEG1/MPEG2 Video and MPEG1/MPEG2 Audio, repsectively. Further indication as to whether the data is MPEG1 or MPEG2 need not be provided in the RTP or MPEG-specific headers of this encapsulation, as this information is available in the ES headers. **/ /*M \emph{RTP RFC2250 MPEG header size.} **/ #define RTP_RFC2250_HDR_SIZE 4 /*M \emph{RTP RFC2250 MPEG audio payload type.} **/ #define RTP_PT_MPA 14 /*M \emph{RTP signed RFC2250 MPEG audio payload type.} This audio payload type was chosen arbitrarily by picking a value from the dynamic payload types. **/ #define RTP_PT_SMPA 97 void rtp_rfc2250_pkt_init(rtp_pkt_t *pkt); /*M \emph{RTP dynamic payload type (used by RFC3119).} **/ #define RTP_DYN 96 void rtp_rfc3119_pkt_init(rtp_pkt_t *pkt); void rtp_vorbis_pkt_init(rtp_pkt_t *pkt); #endif /* RTP_H__ */ /*C **/ poc-0.4.2/scratch/0000775000175000001440000000000010230546573014374 5ustar manuelusers00000000000000poc-0.4.2/aq.h0000664000175000001440000000120310165025647013514 0ustar manuelusers00000000000000#ifndef ADU_QUEUE_H__ #define ADU_QUEUE_H__ #include "adu.h" #include "dlist.h" #include "mp3.h" /*M \emph{MPEG Frame and ADU queue structure.} **/ typedef struct { dlist_head_t frames; dlist_head_t adus; unsigned long size; /* total size of data in queue */ } aq_t; /*C **/ void aq_init(aq_t *q); void aq_destroy(aq_t *q); int aq_add_frame(aq_t *q, mp3_frame_t *frame); int aq_add_adu(aq_t *q, adu_t *adu); mp3_frame_t *aq_get_frame(aq_t *q); adu_t *aq_get_adu(aq_t *q); dlist_t *aq_top_frame(aq_t *q); dlist_t *aq_tail_frame(aq_t *q); dlist_t *aq_top_adu(aq_t *q); dlist_t *aq_tail_adu(aq_t *q); #endif /* ADU_QUEUE_H__ */ poc-0.4.2/poc-http-inetd.c0000664000175000001440000000330210210123147015730 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include "network.h" #include "rtp.h" /*M \emph{Print a HTTP failure header to standard out.} **/ static void pob_bad_request(unsigned long code, const char *comment, const char *msg) { printf("HTTP/1.0 %lu %s\r\nConnection: close\r\n\r\n%s\r\n", code, comment, msg); } int pob_http(void) { } /*M \emph{Print usage information.} **/ static void usage(void) { fprintf(stderr, "Usage: ./pob [-s address] [-p port]\n"); fprintf(stderr, "\t-s address : destination address (default 224.0.1.23)\n"); fprintf(stderr, "\t-p port : destination port (default 1500)\n"); } /*M **/ int main(int argc, char *argv[]) { int retval = EXIT_SUCCESS; char *address = NULL; int port = 1500; address = strdup("224.0.1.23"); int c; while ((c = getopt(argc, argv, "hs:p:")) >= 0) { switch (c) { case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = atoi(optarg); break; case 'h': default: usage(); retval = EXIT_FAILURE; goto exit; } } if (!pob_http()) { retval = EXIT_FAILURE; goto exit; } if ((sock = net_udp4_recv_socket(address, port)) < 0) { fprintf(stderr, "Could not open socket\n"); retval = EXIT_FAILURE; pob_bad_request(500, "Internal Server Error", ""); goto exit; } printf("HTTP/1.0 200 OK\r\n"); if (!pob_main(sock)) { retval = EXIT_FAILURE; goto exit; } exit: if (address != NULL) free(address); return retval; } /*C **/ poc-0.4.2/mp3cue-main.c0000664000175000001440000001463610204451551015231 0ustar manuelusers00000000000000#include "conf.h" #include #include #include #include #include #ifdef WITH_ID3TAG #include #endif /* WITH_ID3TAG */ #ifdef NEED_GETOPT_H__ #include #endif /* NEED_GETOPT_H__ */ #include "aq.h" #include "file.h" #include "mp3cue.h" #include "mp3.h" #include "id3.h" /*M MP3 Cue structure that will get filled by the parser. **/ mp3cue_file_t *yymp3_cue_file = NULL; int yyparse(); static void usage(void) { printf("Usage: mp3cue -c cuefile mp3file\n"); printf("-c cuefile: cut according to cue file\n"); } static void format_time(unsigned long time, char *str, unsigned int len) { unsigned long ms = time % 1000; time /= 1000; unsigned long secs = time % 60; time /= 60; unsigned long minutes = time; time /= 60; unsigned long hours = time; snprintf(str, len, "%.2lu:%.2lu:%.2lu+%.3lu", hours, minutes, secs, ms); } int mp3cue_write_id3(file_t *outfile, mp3cue_file_t *cuefile, mp3cue_track_t *track) { return id3_write_tag(outfile, cuefile->title, track->performer ? track->performer : cuefile->performer, track->title, track->number, "MP3 generated by mp3cue (http://bl0rg.net/software/poc/)"); return 1; } int main(int argc, char *argv[]) { char *cuefilename = NULL, *mp3filename = NULL; int retval = EXIT_SUCCESS; FILE *cuein = NULL; mp3cue_track_t *cuetracks = NULL; int c; while ((c = getopt(argc, argv, "c:C:")) >= 0) { switch (c) { case 'c': if (cuefilename != NULL) free(cuefilename); cuefilename = strdup(optarg); break; case 'C': break; default: usage(); goto exit; } } if (optind == argc) { usage(); goto exit; } mp3filename = argv[optind]; if ((cuefilename == NULL) || (mp3filename == NULL)) { usage(); retval = EXIT_FAILURE; goto exit; } /*M Initialize the mp3 cue structure. **/ mp3cue_file_t cuefile; cuetracks = malloc(sizeof(mp3cue_track_t) * MP3CUE_DEFAULT_TRACK_NUMBER); if (cuetracks == NULL) { fprintf(stderr, "Could not allocate memory for tracks\n"); retval = EXIT_FAILURE; goto exit; } cuefile.tracks = cuetracks; cuefile.track_number = 0; cuefile.max_track_number = MP3CUE_DEFAULT_TRACK_NUMBER; yymp3_cue_file = &cuefile; strncpy(cuefile.title, cuefilename, MP3CUE_MAX_STRING_LENGTH); /*M Open the input file. **/ cuein = fopen(cuefilename, "r"); if (cuein == NULL) { fprintf(stderr, "Could not open cuefile %s\n", cuefilename); retval = EXIT_FAILURE; goto exit; } /*M Parse the input file. **/ extern FILE* yyin; yyin = cuein; if (yyparse() != 0) { retval = EXIT_FAILURE; goto exit; } /*M Open the MP3 file. **/ file_t mp3file; if (!file_open_read(&mp3file, mp3filename)) { fprintf(stderr, "Could not open mp3 file: %s\n", mp3filename); retval = EXIT_FAILURE; return 0; } aq_t qin; aq_init(&qin); unsigned long current = 0; /*M For each track, cut out the relevant part and save it. **/ unsigned int i; for (i = 0; i < cuefile.track_number; i++) { char outfilename[MP3CUE_MAX_STRING_LENGTH * 3 + 1]; if (strlen(cuefile.tracks[i].performer) > 0 && strlen(cuefile.tracks[i].title) > 0) { snprintf(outfilename, MP3CUE_MAX_STRING_LENGTH * 3, "%02d. %s - %s.mp3", cuefile.tracks[i].number, cuefile.tracks[i].performer, cuefile.tracks[i].title); } else { snprintf(outfilename, MP3CUE_MAX_STRING_LENGTH * 3, "%02d. %s.mp3", cuefile.tracks[i].number, cuefile.title); } aq_t qout; aq_init(&qout); /*M Open the output MP3 file. **/ file_t outfile; if (!file_open_write(&outfile, outfilename)) { fprintf(stderr, "Could not open mp3 file: %s\n", outfilename); file_close(&mp3file); retval = EXIT_FAILURE; goto exit; } /* end time in msecs */ unsigned long end = (((cuefile.tracks[i].index.minutes * 60) + cuefile.tracks[i].index.seconds) * 100 + cuefile.tracks[i].index.centiseconds) * 10; char from_buf[256], to_buf[256]; format_time(current, from_buf, sizeof(from_buf)); format_time(end, to_buf, sizeof(to_buf)); printf("Extracting track %d (%s): %s - %s...\n", i, outfilename, from_buf, end ? to_buf : "end"); /* write id3 tags */ if (!mp3cue_write_id3(&outfile, &cuefile, &cuefile.tracks[i])) { fprintf(stderr, "Could not write id3 tags to file: %s\n", outfilename); file_close(&outfile); file_close(&mp3file); retval = EXIT_FAILURE; goto exit; } /*M Read in the input file Read while current < end or till the end of the file if it's the last track. **/ while ((current < end) || (i == (cuefile.track_number - 1))) { mp3_frame_t frame; if (mp3_next_frame(&mp3file, &frame) > 0) { if (aq_add_frame(&qin, &frame)) { adu_t *adu = aq_get_adu(&qin); assert(adu != NULL); if (aq_add_adu(&qout, adu)) { mp3_frame_t *frame_out = aq_get_frame(&qout); assert(frame_out != NULL); memset(frame_out->raw, 0, 4 + frame_out->si_size); if (!mp3_fill_hdr(frame_out) || !mp3_fill_si(frame_out) || (mp3_write_frame(&outfile, frame_out) <= 0)) { fprintf(stderr, "Could not write frame\n"); file_close(&mp3file); file_close(&outfile); retval = 1; goto exit; } free(frame_out); } free(adu); } current += frame.usec / 1000; } else { if (i != (cuefile.track_number - 1)) fprintf(stderr, "Could not read the next frame from the mp3 file...\n"); break; } } /*M Close the output file. **/ file_close(&outfile); aq_destroy(&qout); fprintf(stderr, "%s written\n", outfilename); } /*M Close the input file. **/ file_close(&mp3file); aq_destroy(&qin); /*M Cleanup the data structures. **/ exit: if (cuein != NULL) fclose(cuein); if (cuetracks != NULL) free(cuetracks); if (cuefilename != NULL) free(cuefilename); return retval; } /*M **/ poc-0.4.2/fec-group.c0000664000175000001440000002251610214014115014766 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include "fec.h" #include "fec-group.h" /*M \emph{Initialize a FEC group structure to hold incoming packets.} **/ void fec_group_init(fec_group_t *group, unsigned char fec_k, unsigned char fec_n, unsigned char seq, unsigned long tstamp, unsigned short fec_len) { assert(group != NULL); group->fec_k = fec_k; group->fec_n = fec_n; group->seq = seq; group->tstamp = tstamp; group->fec_len = fec_len; group->rcvd_pkts = 0; group->buf = malloc(sizeof(unsigned char) * fec_n * fec_len); assert(group->buf != NULL); group->lengths = malloc(sizeof(unsigned int) * fec_n); assert(group->lengths != NULL); /* init pointers */ int i; for (i = 0; i < fec_n; i++) { group->lengths[i] = 0; } group->decoded = 0; } /*M \emph{Destroy a FEC group structure.} **/ void fec_group_destroy(fec_group_t *group) { assert(group != NULL); if (group->buf) { free(group->buf); group->buf = NULL; } if (group->lengths) { free(group->lengths); group->lengths = NULL; } fec_group_clear(group); } /*M \emph{Clear a FEC group structure.} **/ void fec_group_clear(fec_group_t *group) { group->buf = NULL; group->lengths = NULL; group->fec_k = group->fec_n = group->tstamp = 0; group->fec_len = 0; group->rcvd_pkts = 0; } /*M \emph{Print debug information about a FEC group.} **/ void fec_group_print(fec_group_t *group) { assert(group != NULL); fprintf(stderr, "Group %p tstamp: %lu\n", group, group->tstamp); fprintf(stderr, "k: %d, n: %d, len: %u\n", group->fec_k, group->fec_n, group->fec_len); fprintf(stderr, "received packets: %u/%u\n", group->rcvd_pkts, group->fec_k); int i; for (i = 0; i < group->fec_n; i++) { if (group->lengths[i] == 0) { fprintf(stderr, "%d: not received\n", i); } else { fprintf(stderr, "%d: received\n", i); } } } /*M \emph{Insert a received FEC packet into a FEC group.} **/ void fec_group_insert_pkt(fec_group_t *group, fec_pkt_t *pkt) { assert(group != NULL); assert(pkt != NULL); /* sanity checks, no real error handling yet */ assert(pkt->hdr.packet_seq < group->fec_n); assert(pkt->hdr.len <= group->fec_len); /* XXX das kann passieren wenn der streamer restartet, und versehentlich die selbe groupseqnumber erwischt. */ assert(pkt->hdr.group_tstamp == group->tstamp); /* check if packet already received */ if (group->lengths[pkt->hdr.packet_seq] == 0) { unsigned char *ptr = group->buf + pkt->hdr.packet_seq * group->fec_len; memcpy(ptr, pkt->payload, pkt->hdr.len); if (pkt->hdr.len < group->fec_len) { memset(ptr + pkt->hdr.len, 0, group->fec_len - pkt->hdr.len); } group->lengths[pkt->hdr.packet_seq] = pkt->hdr.len; group->rcvd_pkts++; } } /*M \emph{Decode a FEC group into an ADU queue.} If the group is not complete, the lower packets (with \verb|packet_seq| $<$ \verb|fec_k|) are added to the ADU. **/ int fec_group_decode(fec_group_t *group) { assert(group != NULL); if (group->decoded) return 1; /* check if enough packets in the group have been received to * recover the complete source data. */ if (group->rcvd_pkts >= group->fec_k) { /* we have enough packets in the fec group */ unsigned int idxs[group->fec_k]; /* create index array and pointer array. */ int i, j; for (i = 0, j = 0; i < group->fec_n; i++) { if (group->lengths[i] > 0) { idxs[j] = i; j++; if (j == group->fec_k) break; } } assert(j == group->fec_k); /* create the fec structure. */ fec_t *fec = fec_new(group->fec_k, group->fec_n); assert(fec != NULL); /* decode the fec group. */ if (!fec_decode(fec, group->buf, idxs, group->fec_len)) { fprintf(stderr, "Could not decode FEC group\n"); fec_free(fec); return 0; } fec_free(fec); group->decoded = 1; return 1; } else { return 0; } } int fec_group_decode_to_adus(fec_group_t *group, aq_t *aq) { assert(group != NULL); assert(aq != NULL); if (fec_group_decode(group)) { /*M Add the adus to the adu queue. **/ int i; for (i = 0; i < group->fec_k; i++) { adu_t adu; memcpy(adu.raw, group->buf + i * group->fec_len, group->fec_len); if (!mp3_unpack(&adu)) { fprintf(stderr, "Error unpacking the mp3 adu\n"); return 0; } aq_add_adu(aq, &adu); } } else { /*M We don't have enough packets in the group to recover the whole source data, add only the uncoded ADUs we received (systematic encoding). **/ int i; for (i = 0; i < group->fec_k; i++) { if (group->lengths[i] > 0) { adu_t adu; memcpy(adu.raw, group->buf + i * group->fec_len, group->fec_len); if (!mp3_unpack(&adu)) { fprintf(stderr, "Error unpacking the mp3 adu\n"); return 0; } aq_add_adu(aq, &adu); } } } return 1; } #ifdef FEC_GROUP_TEST unsigned char fec_k = 20; unsigned char fec_n = 25; unsigned long cksum(unsigned char *buf, int cnt) { unsigned long res = 0; int i; for (i = 0; i < cnt; i++) res += buf[i]; return res; } int main(int argc, char *argv[]) { char *f[2]; if (!(f[0] = *++argv) || !(f[1] = *++argv)) { fprintf(stderr, "Usage: mp3-write mp3in mp3out\n"); return 1; } file_t in; if (!file_open_read(&in, f[0])) { fprintf(stderr, "Could not open mp3 file for read: %s\n", f[0]); return 1; } file_t out; if (!file_open_write(&out, f[1])) { fprintf(stderr, "Could not open mp3 file for write: %s\n", f[1]); file_close(&in); return 1; } aq_t qin, qout; aq_init(&qin); aq_init(&qout); adu_t *in_adus[fec_k]; unsigned int cnt = 0; static unsigned long fec_time = 0; fec_t *fec = fec_new(fec_k, fec_n); mp3_frame_t frame; while (mp3_next_frame(&in, &frame) > 0) { static int cin = 0; if (aq_add_frame(&qin, &frame)) { printf("frame\n"); in_adus[cnt] = aq_get_adu(&qin); assert(in_adus[cnt] != NULL); /* check if the FEC group is complete */ if (++cnt == fec_k) { unsigned int max_len = 0; unsigned long group_duration = 0; int i; for (i = 0; i < fec_k; i++) { unsigned int adu_len = mp3_frame_size(in_adus[i]); + (in_adus[i]->protected ? 0 : 2) + in_adus[i]->si_size + in_adus[i]->adu_size; if (adu_len > max_len) max_len = adu_len; group_duration += in_adus[i]->usec; } #if 0 fec_time += group_duration; assert(max_len < FEC_PKT_PAYLOAD_SIZE); unsigned char *in_ptrs[fec_k]; unsigned char buf[fec_k * max_len]; unsigned char *ptr = buf; for (i = 0; i < fec_k; i++) { unsigned int adu_len = mp3_frame_size(in_adus[i]); in_ptrs[i] = ptr; memcpy(ptr, in_adus[i]->raw, adu_len); if (adu_len < max_len) memset(ptr + adu_len, 0, max_len - adu_len); ptr += max_len; } fec_group_t group; fec_group_init(&group, fec_k, fec_n, 0, 0, max_len); memset(group.buf, 0, fec_n * max_len); group.tstamp = fec_time; for (i = 0; i < fec_n; i++) { fec_pkt_t pkt; fec_pkt_init(&pkt); pkt.hdr.packet_seq = i; pkt.hdr.fec_k = fec_k; pkt.hdr.fec_n = fec_n; pkt.hdr.fec_len = max_len + 2; pkt.hdr.group_tstamp = fec_time; fec_encode(fec, in_ptrs, pkt.payload, i, max_len); if (i < fec_k) { pkt.hdr.len = mp3_frame_size(in_adus[i]); } else { pkt.hdr.len = max_len; } fec_group_insert_pkt(&group, &pkt); } if (!fec_group_decode(&group, &qout)) { fprintf(stderr, "Could not decode group\n"); return 1; } fec_group_destroy(&group); #endif for (i = 0; i < fec_k; i++) { adu_t adu; memcpy(adu.raw, in_adus[i]->raw, max_len); if (!mp3_unpack(&adu)) { fprintf(stderr, "Error unpacking the mp3 adu\n"); return 0; } aq_add_adu(&qout, &adu); } mp3_frame_t *frame_out; while ((frame_out = aq_get_frame(&qout)) != NULL) { memset(frame_out->raw, 0, 4 + frame_out->si_size); /*M Write packet payload. **/ if (!mp3_fill_hdr(frame_out) || !mp3_fill_si(frame_out) || (mp3_write_frame(&out, frame_out) <= 0)) { fprintf(stderr, "Error writing to stdout\n"); free(frame_out); return 0; } free(frame_out); } for (i = 0; i < fec_k; i++) free(in_adus[i]); cnt = 0; } } /* fgetc(stdin); */ } file_close(&in); file_close(&out); aq_destroy(&qin); aq_destroy(&qout); return 0; } #endif /* FEC_GROUP_TEST */ poc-0.4.2/fec-group.h0000664000175000001440000000307010210123147014767 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include "fec-pkt.h" #include "aq.h" /*M \emph{FEC group structure.} Used to collect packets until enough are available to decode the group. **/ typedef struct fec_group_s { /*M $k$ FEC parameter. At least $k$ packets have to be collected in order to recover the complete source information. **/ unsigned char fec_k; /*M $n$ FEC parameter. The group contains at least $n$ packets. **/ unsigned char fec_n; /*M The maximal length of a packet. Packets with sequence numbers < $k$ can be shorter. **/ unsigned short fec_len; /*M The group sequence number. **/ unsigned char seq; /*M The group timestamp in usecs. **/ unsigned long tstamp; /*M Received packets count. **/ unsigned char rcvd_pkts; /*M Keeps track of received packets. **/ unsigned char *pkts; /*M Buffer to be filled with packet payloads. **/ unsigned char *buf; /* Length of the inserted packets. */ unsigned int *lengths; int decoded; } fec_group_t; void fec_group_init(fec_group_t *group, unsigned char fec_k, unsigned char fec_n, unsigned char seq, unsigned long tstamp, unsigned short fec_len); void fec_group_destroy(fec_group_t *group); void fec_group_clear(fec_group_t *group); void fec_group_insert_pkt(fec_group_t *group, fec_pkt_t *pkt); int fec_group_decode(fec_group_t *group); int fec_group_decode_to_adus(fec_group_t *group, aq_t *aq); poc-0.4.2/libfec-test.c0000664000175000001440000000415310204466440015310 0ustar manuelusers00000000000000#include "conf.h" #include #include #include #include #include #include "pack.h" #include "aq.h" #include "file.h" #include "mp3.h" #include "libfec.h" static void usage(void) { printf("Usage: libfec-test mp3file\n"); } #define min(a,b) ((a) < (b) ? (a) : (b)) static void hexdump(unsigned char *data, unsigned long len) { unsigned long i; for (i = 0; i < len; i += 16) { unsigned long j; fprintf(stderr, "%06lx ", i); for (j = 0; j < min(len - i, 16); j++) fprintf(stderr, "%02x ", data[i + j]); fprintf(stderr, "\n"); } } int main(int argc, char *argv[]) { int retval = EXIT_SUCCESS; if (argc != 2) { usage(); return EXIT_FAILURE; } int fec_k = 20; int fec_n = 25; libfec_init(argv[1], "-"); fec_encode_t *encode = libfec_new_encode(fec_k, fec_n); assert(encode != NULL); unsigned char buf[8192]; unsigned int len; int ret; while ((len = libfec_read_adu(buf, sizeof(buf))) >= 0) { ret = libfec_add_adu(encode, len, buf); assert(ret); static int adu_cnt = 0; /* decode */ if (++adu_cnt == fec_k) { int max_length = libfec_max_length(encode); unsigned char fec_pkts[fec_n][max_length]; unsigned int lengths[fec_n]; int i; for (i = 0; i < fec_n; i++) { lengths[i] = libfec_encode(encode, fec_pkts[i], i, max_length); // assert(lengths[i] != 0); } fec_decode_t *group = libfec_new_group(fec_k, fec_n, max_length); for (i = 0; i < fec_n; i++) { libfec_add_pkt(group, i, lengths[i], fec_pkts[i]); } for (i = 0; i < fec_k; i++) { unsigned char buf[8192]; unsigned int len; len = libfec_decode(group, buf, i, sizeof(buf)); // fprintf(stderr, "decode %d, len %d\n", i, len); // hexdump(buf, len); if (len) { libfec_write_adu(buf, len); } } libfec_delete_group(group); libfec_delete_encode(encode); encode = libfec_new_encode(fec_k, fec_n); assert(encode); adu_cnt = 0; } } libfec_close(); return retval; } poc-0.4.2/pob-3119-rb.c0000664000175000001440000002454310214014115014655 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include #ifdef NEED_GETOPT_H__ #include #endif /* NEED_GETOPT_H__ */ #ifdef WITH_OPENSSL #include #include #include #include #endif /* WITH_OPENSSL */ #include "rtp.h" #include "rtp-rb.h" #include "aq.h" #include "network.h" #ifdef WITH_OPENSSL RSA *rsa = NULL; #endif #define RTP_MINSLEEP 20000 /* 200 ms */ /*M \emph{Structure to hold client accounting information.} This is used to count the number of wrong packets, duplicate packets, out of order packets, unauthenticated packets. **/ typedef struct pob_stat_s { /*M Number of packets received. **/ unsigned int rcvd_pkts; /*M Number of out of order packets received. **/ unsigned int ooo_pkts; /*M Number of duplicated packets received. **/ unsigned int dup_pkts; /*M Number of bad packets received. **/ unsigned int bad_pkts; #ifdef WITH_OPENSSL /*M Badly signed packets. **/ unsigned int sign_pkts; #endif /*M Number of buffer overflows. **/ unsigned int buf_ofs; /*M Number of buffer underflows. **/ unsigned int buf_ufs; } pob_stat_t; static pob_stat_t pob_stats = { 0, 0, 0, 0, 0 #ifdef WITH_OPENSSL ,0 #endif }; /*M \emph{Timestamp of last played packet.} **/ static unsigned long tstamp_last = 0; /*M **/ int pob_insert_pkt(rtp_pkt_t *pkt) { assert(pkt != NULL); /*M We have received a packet. **/ pob_stats.rcvd_pkts++; /*M Verify packet if Openssl is activated. **/ #ifdef WITH_OPENSSL if (rsa) { if ((pkt->b.pt != RTP_PT_SMPA) || !rtp_pkt_verify(pkt, rsa)) { pob_stats.sign_pkts++; return 0; } } #endif int num = 0; /* insert packet into ringbuffer */ if (rtp_rb_length() > 0) { /* get index of first packet */ rtp_pkt_t *firstpkt = rtp_rb_first(); assert(firstpkt != NULL); assert(firstpkt->length != 0); num = net_seqnum_diff(firstpkt->b.seq, pkt->b.seq, 1 << 16); } if (!rtp_rb_insert_pkt(pkt, num)) { #ifdef DEBUG fprintf(stderr, "ring buffer full\n"); #endif rtp_rb_clear(); tstamp_last = pkt->timestamp; return pob_insert_pkt(pkt); } else { return 1; } } int pob_recv_pkt(int sock, rtp_pkt_t *pkt) { struct timeval t_out; t_out.tv_sec = 0; t_out.tv_usec = RTP_MINSLEEP; fd_set fds; FD_ZERO(&fds); FD_SET(sock, &fds); /*M Wait for network input or for timeout. **/ int ret = select(sock + 1, &fds, NULL, NULL, &t_out); /*M Check for interrupted system call. **/ if (ret == -1) { if ((errno == EINTR) || (errno == EAGAIN)) { return 0; } else { perror("select"); return -1; } } /*M If there is network input, read incoming packet. **/ if (FD_ISSET(sock, &fds)) { rtp_rfc3119_pkt_init(pkt); if (rtp_pkt_read(pkt, sock) <= 0) { return -1; } else { return 1; } } return 0; } unsigned long cksum(char *data, int len) { unsigned long res = 0; int i; for (i = 0; i < len; i++) res += data[i]; return res; } /*M \emph{Simple RTP RFC3119 streaming client main loop.} The mainloop calls the prebuffering routine each time the receiving list is empty, then receives packets and writes the packets in the buffering queue out to standard output. **/ int pob_mainloop(int sock, int quiet) { int retval = 0; /*M Initialize the ADU to frame ADU queue. **/ aq_t frame_queue; aq_init(&frame_queue); int finished = 0; while (!finished) { static int prebuffering = 0; rtp_pkt_t pkt; if (rtp_rb_cnt == 0) { prebuffering = 1; } /*M Receive next packet. */ switch (pob_recv_pkt(sock, &pkt)) { case 0: break; case -1: finished = 1; continue; default: /*M Insert new packet into the buffering list. **/ if (!pob_insert_pkt(&pkt)) { retval = 0; goto exit; } } static unsigned long time_last; unsigned long time_now; struct timeval tv; gettimeofday(&tv, NULL); time_now = tv.tv_sec * 90000 + (unsigned long)(tv.tv_usec / 11.111); if (prebuffering == 1) { if (rtp_rb_cnt >= (rtp_rb_size / 2)) { rtp_pkt_t *firstpkt = rtp_rb_first(); assert(firstpkt != NULL); assert(firstpkt->length != 0); tstamp_last = firstpkt->timestamp; time_last = time_now; prebuffering = 0; if (!quiet) fprintf(stderr, "\n"); } else { /*M Print prebuffering information. **/ if (!quiet) fprintf(stderr, "Prebuffering: %.2f%%\r", (float)rtp_rb_cnt / (rtp_rb_size / 2.0) * 100.0); continue; } } /*M Print client information. **/ if (!quiet) { static int count = 0; if ((count++ % 10) == 0) { fprintf(stderr, "pkts: %.8u\tdups: %.6u\tdrop: %.6u\tbuf: %.6u len:%.6u\t\r", pob_stats.rcvd_pkts, pob_stats.dup_pkts, pob_stats.ooo_pkts, rtp_rb_cnt, rtp_rb_length()); } } #ifdef DEBUG rtp_rb_print(); #endif unsigned long tstamp_now = tstamp_last + (time_now - time_last); while (rtp_rb_length() > 0) { rtp_pkt_t *pkt = rtp_rb_first(); assert(pkt != NULL); if (pkt->length != 0) { /* boeser hack XXX */ if (pkt->timestamp > (tstamp_now + 3000)) break; /*M Unpack ADU and insert into ADU queue. **/ unsigned char *ptr = pkt->data + pkt->hlen; if (pkt->length > ((1 << 6) - 1)) ptr++; adu_t adu; memcpy(adu.raw, ptr, pkt->length); if (!mp3_unpack(&adu)) { fprintf(stderr, "Error unpacking the mp3 adu\n"); pkt->length = 0; rtp_rb_cnt--; retval = 0; goto exit; } if (aq_add_adu(&frame_queue, &adu)) { /*M If a frame could be generated, write it out to standard out. **/ mp3_frame_t *frame = aq_get_frame(&frame_queue); assert(frame != NULL); memset(frame->raw, 0, 4 + frame->si_size); /*M Write packet payload. **/ if (!mp3_fill_hdr(frame) || !mp3_fill_si(frame) || (write(STDOUT_FILENO, frame->raw, frame->frame_size) < (int)frame->frame_size)) { fprintf(stderr, "Error writing to stdout\n"); free(frame); pkt->length = 0; rtp_rb_cnt--; retval = 0; goto exit; } time_last = time_now; tstamp_last = tstamp_now; free(frame); } } rtp_rb_pop(); } } exit: /*M Destroy the ADU queue. **/ aq_destroy(&frame_queue); return retval; } /*M \emph{Print RFC3119 RTP client usage.} **/ static void usage(void) { fprintf(stderr, "Usage: ./pob [-s address] [-p port] [-b size] [-t time] [-q]"); #ifdef WITH_OPENSSL fprintf(stderr, "[-c cert]"); #endif fprintf(stderr, "\n"); fprintf(stderr, "\t-s address : destination address (default 0.0.0.0 or ff02::4)\n"); fprintf(stderr, "\t-p port : destination port (default 1500)\n"); fprintf(stderr, "\t-b size : maximal number of packets in buffer (default 128)\n"); fprintf(stderr, "\t-q : quiet\n"); #ifdef WITH_OPENSSL fprintf(stderr, "\t-c cert : verify packets with rsa certificate\n"); #endif } /*M \emph{RFC3119 RTP client entry routine.} **/ int main(int argc, char *argv[]) { char *address = NULL; unsigned short port = 1500; unsigned int buffer_size = 128; int retval = EXIT_SUCCESS, quiet = 0; #ifdef WITH_OPENSSL X509 *x509 = NULL; EVP_PKEY *pkey = NULL; #endif /*M Process the command line arguments. **/ int c; while ((c = getopt(argc, argv, "hs:p:b:t:q" #ifdef WITH_OPENSSL "c:" #endif )) >= 0) { switch (c) { case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = atoi(optarg); break; case 'b': buffer_size = (unsigned short)atoi(optarg); break; case 'q': quiet = 1; break; /*M If Openssl is used, read in the RSA certificate. **/ #ifdef WITH_OPENSSL case 'c': { FILE *f; if (x509) { X509_free(x509); x509 = NULL; } if (pkey) { EVP_PKEY_free(pkey); pkey = NULL; rsa = NULL; } if (!(f = fopen(optarg, "r")) || !PEM_read_X509(f, &x509, NULL, NULL) || !(pkey = X509_get_pubkey(x509))) { fprintf(stderr, "Could not read certificate %s\n", optarg); if (f) fclose(f); retval = EXIT_FAILURE; goto exit; } fclose(f); if (pkey->type != EVP_PKEY_RSA) { fprintf(stderr, "Key is not a RSA key\n"); retval = EXIT_FAILURE; goto exit; } rsa = pkey->pkey.rsa; break; } #endif case 'h': default: usage(); retval = EXIT_SUCCESS; goto exit; } } /*M Initialize the ring buffer. **/ rtp_rb_init(buffer_size); if (address == NULL) { #ifdef WITH_IPV6 address = strdup("ff02::4"); #else address = strdup("0.0.0.0"); #endif /* WITH_IPV6 */ } /*M Create the receiving socket. **/ int sock; #ifdef WITH_IPV6 sock = net_udp6_recv_socket(address, port); #else sock = net_udp4_recv_socket(address, port); #endif /* WITH_IPV6 */ if (sock < 0) { fprintf(stderr, "Could not open socket\n"); retval = EXIT_FAILURE; goto exit; } if (!pob_mainloop(sock, quiet)) retval = EXIT_FAILURE; if (close(sock) < 0) perror("close"); exit: rtp_rb_destroy(); #ifdef WITH_OPENSSL if (pkey) EVP_PKEY_free(pkey); if (x509) X509_free(x509); #endif if (address != NULL) free(address); return retval; } /*C **/ poc-0.4.2/vorbis.c0000664000175000001440000000327110210123147014402 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include "ogg.h" #include "buf.h" #include "vorbis.h" /*M \emph{Initialize a Vorbis stream.} **/ void vorbis_stream_init(vorbis_stream_t *vorbis) { assert(vorbis != NULL); ogg_page_init(&vorbis->page); assert(vorbis->page.raw.data != NULL); vorbis->segment = 0; vorbis->hdr_pages_cnt = 0; int i; for (i = 0; i < VORBIS_MAX_HDR_PAGES; i++) ogg_page_init(vorbis->hdr_pages + i); buf_alloc(&vorbis->id_hdr, 1000); assert(vorbis->id_hdr.data != NULL); buf_alloc(&vorbis->comment_hdr, 1000); assert(vorbis->comment_hdr.data != NULL); buf_alloc(&vorbis->setup_hdr, 2000); assert(vorbis->setup_hdr.data != NULL); } /*M \emph{Free the structures allocated inside the Vorbis stream.} **/ void vorbis_stream_destroy(vorbis_stream_t *vorbis) { ogg_page_destroy(&vorbis->page); vorbis->segment = 0; int i; for (i = 0; i < VORBIS_MAX_HDR_PAGES; i++) ogg_page_destroy(vorbis->hdr_pages + i); buf_free(&vorbis->id_hdr); buf_free(&vorbis->comment_hdr); buf_free(&vorbis->setup_hdr); } /*M \emph{Check if the buffer contains a Vorbis header of type \verb|type|.} **/ int vorbis_check_packet(buf_t *buf, unsigned char type) { assert(buf != NULL); if (buf->len < VORBIS_HDR_SIZE) return 0; if (buf->data[0] != type) return 0; if ((buf->data[1] != VORBIS_SYNC_HDR_BYTE1) || (buf->data[2] != VORBIS_SYNC_HDR_BYTE2) || (buf->data[3] != VORBIS_SYNC_HDR_BYTE3) || (buf->data[4] != VORBIS_SYNC_HDR_BYTE4) || (buf->data[5] != VORBIS_SYNC_HDR_BYTE5) || (buf->data[6] != VORBIS_SYNC_HDR_BYTE6)) return 0; return 1; } /*C **/ poc-0.4.2/mp3-sf.c0000664000175000001440000002516410210123147014210 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include "bv.h" #include "mp3.h" /*M \emph{Read scalefactor information.} **/ int mp3_read_sf(mp3_frame_t *frame) { assert(frame != NULL); unsigned int granule_offset = 0; unsigned int i; for (i = 0; i < 2; i++) { unsigned int nch = (frame->mode != 3) ? 2 : 1; unsigned int j; for (j = 0; j < nch; j++) { mp3_granule_t *gr = &frame->si.channel[j].granule[i]; mp3_sf_t *sf = &gr->sf; unsigned int bit0 = granule_offset & 7; bv_t bv; bv_init(&bv, mp3_frame_data_begin(frame) + (granule_offset >> 3), gr->part2_length + bit0); if (bit0) bv_get_bits(&bv, bit0); granule_offset += gr->part2_3_length; if ((gr->blocksplit_flag == 1) && (gr->block_type == 2)) { /* no scale factor selection information, 3 short windows */ if (gr->switch_point) { /* split of long and short transforms at 8 */ unsigned int sfb; if (gr->slen0 > 0) { for (sfb = 0; sfb < 8; sfb++) sf->l[sfb] = bv_get_bits(&bv, gr->slen0); for (sfb = 3; sfb < 6; sfb++) { sf->s[0][sfb] = bv_get_bits(&bv, gr->slen0); sf->s[1][sfb] = bv_get_bits(&bv, gr->slen0); sf->s[2][sfb] = bv_get_bits(&bv, gr->slen0); } } if (gr->slen1 > 0) { for (sfb = 6; sfb < 12; sfb++) { sf->s[0][sfb] = bv_get_bits(&bv, gr->slen1); sf->s[1][sfb] = bv_get_bits(&bv, gr->slen1); sf->s[2][sfb] = bv_get_bits(&bv, gr->slen1); } } } else { /* no long transforms */ unsigned int sfb; if (gr->slen0 > 0) { for (sfb = 0; sfb < 6; sfb ++) { sf->s[0][sfb] = bv_get_bits(&bv, gr->slen0); sf->s[1][sfb] = bv_get_bits(&bv, gr->slen0); sf->s[2][sfb] = bv_get_bits(&bv, gr->slen0); } } if (gr->slen1 > 0) { for (sfb = 6; sfb < 12; sfb++) { sf->s[0][sfb] = bv_get_bits(&bv, gr->slen1); sf->s[1][sfb] = bv_get_bits(&bv, gr->slen1); sf->s[2][sfb] = bv_get_bits(&bv, gr->slen1); } } } } else { /* long blocks types 0, 1, 3 */ if (i == 0) { /* first granule, no scalefactor selection information to apply */ unsigned int sfb; if (gr->slen0 > 0) for (sfb = 0; sfb < 11; sfb++) sf->l[sfb] = bv_get_bits(&bv, gr->slen0); if (gr->slen1 > 0) for (sfb = 11; sfb < 21; sfb++) sf->l[sfb] = bv_get_bits(&bv, gr->slen1); } else { /* second granule, check scalefactor selection information */ mp3_channel_t *channel = &frame->si.channel[j]; mp3_sf_t *sf1 = &channel->granule[0].sf; unsigned int sfb; if (gr->slen0 > 0) { /* cb = 0 */ if (channel->scfsi[0]) { for (sfb = 0; sfb < 6; sfb++) sf->l[sfb] = sf1->l[sfb]; } else { for (sfb = 0; sfb < 6; sfb++) sf->l[sfb] = bv_get_bits(&bv, gr->slen0); } /* cb = 1 */ if (channel->scfsi[1]) { for (sfb = 6; sfb < 11; sfb++) sf->l[sfb] = sf1->l[sfb]; } else { for (sfb = 6; sfb < 11; sfb++) sf->l[sfb] = bv_get_bits(&bv, gr->slen0); } } if (gr->slen1 > 0) { /* cb = 2 */ if (channel->scfsi[2]) { for (sfb = 11; sfb < 16; sfb++) sf->l[sfb] = sf1->l[sfb]; } else { for (sfb = 11; sfb < 16; sfb++) sf->l[sfb] = bv_get_bits(&bv, gr->slen1); } /* cb = 3 */ if (channel->scfsi[3]) { for (sfb = 16; sfb < 21; sfb++) sf->l[sfb] = sf1->l[sfb]; } else { for (sfb = 16; sfb < 21; sfb++) sf->l[sfb] = bv_get_bits(&bv, gr->slen1); } } } } } } return 1; } /*M \emph{Fill MPEG frame with scalefactor information.} **/ int mp3_fill_sf(mp3_frame_t *frame) { assert(frame != NULL); unsigned int granule_offset = 0; unsigned int i; for (i = 0; i < 2; i++) { unsigned int nch = (frame->mode != 3) ? 2 : 1; unsigned int j; for (j = 0; j < nch; j++) { mp3_granule_t *gr = &frame->si.channel[j].granule[i]; mp3_sf_t *sf = &gr->sf; unsigned int bit0 = granule_offset & 7; bv_t bv; bv_init(&bv, mp3_frame_data_begin(frame) + (granule_offset >> 3), gr->part2_length + bit0); if (bit0) bv_get_bits(&bv, bit0); granule_offset += gr->part2_3_length; if ((gr->blocksplit_flag == 1) && (gr->block_type == 2)) { /* no scale factor selection information, 3 short windows */ if (gr->switch_point) { /* split of long and short transforms at 8 */ unsigned int sfb; if (gr->slen0 > 0) { for (sfb = 0; sfb < 8; sfb++) bv_put_bits(&bv, sf->l[sfb], gr->slen0); for (sfb = 3; sfb < 6; sfb++) { bv_put_bits(&bv, sf->s[0][sfb], gr->slen0); bv_put_bits(&bv, sf->s[1][sfb], gr->slen0); bv_put_bits(&bv, sf->s[2][sfb], gr->slen0); } } if (gr->slen1 > 0) { for (sfb = 6; sfb < 12; sfb++) { bv_put_bits(&bv, sf->s[0][sfb], gr->slen1); bv_put_bits(&bv, sf->s[1][sfb], gr->slen1); bv_put_bits(&bv, sf->s[2][sfb], gr->slen1); } } } else { /* no long transforms */ unsigned int sfb; if (gr->slen0 > 0) { for (sfb = 0; sfb < 6; sfb ++) { bv_put_bits(&bv, sf->s[0][sfb], gr->slen0); bv_put_bits(&bv, sf->s[1][sfb], gr->slen0); bv_put_bits(&bv, sf->s[2][sfb], gr->slen0); } } if (gr->slen1 > 0) { for (sfb = 6; sfb < 12; sfb++) { bv_put_bits(&bv, sf->s[0][sfb], gr->slen1); bv_put_bits(&bv, sf->s[1][sfb], gr->slen1); bv_put_bits(&bv, sf->s[2][sfb], gr->slen1); } } } } else { /* long blocks types 0, 1, 3 */ if (i == 0) { /* first granule, no scalefactor selection information to apply */ unsigned int sfb; if (gr->slen0 > 0) for (sfb = 0; sfb < 11; sfb++) bv_put_bits(&bv, sf->l[sfb], gr->slen0); if (gr->slen1 > 0) for (sfb = 11; sfb < 21; sfb++) bv_put_bits(&bv, sf->l[sfb], gr->slen1); } else { /* second granule, check scalefactor selection information */ mp3_channel_t *channel = &frame->si.channel[j]; unsigned int sfb; if (gr->slen0 > 0) { /* cb = 0 */ if (!channel->scfsi[0]) for (sfb = 0; sfb < 6; sfb++) bv_put_bits(&bv, sf->l[sfb], gr->slen0); /* cb = 1 */ if (!channel->scfsi[1]) for (sfb = 6; sfb < 11; sfb++) bv_put_bits(&bv, sf->l[sfb], gr->slen0); } if (gr->slen1 > 0) { /* cb = 2 */ if (!channel->scfsi[2]) for (sfb = 11; sfb < 16; sfb++) bv_put_bits(&bv, sf->l[sfb], gr->slen1); /* cb = 3 */ if (!channel->scfsi[3]) for (sfb = 16; sfb < 21; sfb++) bv_put_bits(&bv, sf->l[sfb], gr->slen1); } } } } } return 1; } /*C **/ #ifdef MP3SF_TEST #include #include #include "aq.h" unsigned long cksum(unsigned char *buf, int cnt) { unsigned long res = 0; int i; for (i = 0; i < cnt; i++) res += buf[i]; return res; } int main(int argc, char *argv[]) { char *f[2]; if (!(f[0] = *++argv) || !(f[1] = *++argv)) { fprintf(stderr, "Usage: mp3-write mp3in mp3out\n"); return 1; } mp3_file_t in; if (!mp3_open_read(&in, f[0])) { fprintf(stderr, "Could not open mp3 file for read: %s\n", f[0]); return 1; } mp3_file_t out; if (!mp3_open_write(&out, f[1])) { fprintf(stderr, "Could not open mp3 file for write: %s\n", f[1]); mp3_close(&in); return 1; } aq_t qin, qout; aq_init(&qin); aq_init(&qout); mp3_frame_t frame = {0}; while (mp3_next_frame(&in, &frame) > 0) { static int cin = 0; printf("%d in, cksum %ld\n", cin++, cksum(frame.raw, frame.frame_size)); if (aq_add_frame(&qin, &frame)) { adu_t *adu = aq_get_adu(&qin); assert(adu != NULL); static int cadu = 0; mp3_read_sf(adu); printf("frame %d\n", cadu); unsigned int i; for (i = 0; i < 2; i++) { unsigned int j; for (j = 0; j < 2; j++) { unsigned int l; printf("ch %d, gr %d: ", j, i); for (l = 0; l < 22; l++) printf("%d, ", adu->si.channel[j].granule[i].sf.l[l]); printf("\n"); } } unsigned oldck = cksum(adu->raw, MP3_RAW_SIZE); mp3_fill_sf(adu); unsigned newck = cksum(adu->raw, MP3_RAW_SIZE); if (newck != oldck) printf("corruption on frame %d\n", cadu); mp3_read_sf(adu); for (i = 0; i < 2; i++) { unsigned int j; for (j = 0; j < 2; j++) { unsigned int l; printf("ch %d, gr %d: ", j, i); for (l = 0; l < 22; l++) printf("%d, ", adu->si.channel[j].granule[i].sf.l[l]); printf("\n"); } } cadu++; if (aq_add_adu(&qout, adu)) { mp3_frame_t *frame_out = aq_get_frame(&qout); assert(frame_out != NULL); static int cout = 0; memset(frame_out->raw, 0, 4 + frame_out->si_size); if (!mp3_fill_hdr(frame_out) || !mp3_fill_si(frame_out) || (mp3_write_frame(&out, frame_out) <= 0)) { fprintf(stderr, "Could not write frame\n"); mp3_close(&in); mp3_close(&out); return 1; } printf("%d out, cksum %ld\n", cout++, cksum(frame_out->raw, frame_out->frame_size)); free(frame_out); } free(adu); } /* fgetc(stdin); */ } mp3_close(&in); mp3_close(&out); aq_destroy(&qin); aq_destroy(&qout); return 0; } #endif poc-0.4.2/mp3cut.c0000664000175000001440000002343010210454261014314 0ustar manuelusers00000000000000#include "conf.h" #include #include #include #include #include #include "aq.h" #include "file.h" #include "mp3.h" #include "id3.h" #define min(a, b) ((a) < (b) ? (a) : (b)) static void usage(void) { printf("Usage: mp3cut [-o outputfile] [-T title] [-A artist] [-N album-name] [-t [hh:]mm:ss[+ms]-[hh:]mm:ss[+ms]] mp3 [-t ...] mp3\n"); printf("-o output: Output file, default mp3file.out.mp3\n"); } static int parse_number(const char *str, unsigned long *result) { char buf[16]; char *endptr = NULL; strncpy(buf, str, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; *result = strtoul(buf, &endptr, 10); if ((*endptr != '\0') || (endptr == buf)) return -1; return 0; } static int parse_time(const char *str, unsigned long *time) { /* strtok madness */ char strbuf[256]; strncpy(strbuf, str, sizeof(strbuf)); strbuf[sizeof(strbuf) - 1] = '\0'; *time = 0; char *token; unsigned long numbers[4]; unsigned long cnt = 0; token = strtok(strbuf, "+:"); if ((token == NULL) || (parse_number(token, &numbers[cnt++]) < 0)) return -1; token = strtok(NULL, "+:"); if ((token == NULL) || (parse_number(token, &numbers[cnt++]) < 0)) return -1; token = strtok(NULL, "+:"); if (token && (parse_number(token, &numbers[cnt++]) < 0)) return -1; token = strtok(NULL, "+:"); if (token && (parse_number(token, &numbers[cnt++]) < 0)) return -1; int mspresent = (strchr(str, '+') != NULL); unsigned long hours = 0, minutes = 0, seconds = 0, ms = 0; switch (cnt) { case 2: if (mspresent) return -1; minutes = numbers[0]; seconds = numbers[1]; break; case 3: if (mspresent) { minutes = numbers[0]; seconds = numbers[1]; ms = numbers[2]; } else { hours = numbers[0]; minutes = numbers[1]; seconds = numbers[2]; if (minutes >= 60) return -1; } break; case 4: hours = numbers[0]; minutes = numbers[1]; seconds = numbers[2]; ms = numbers[3]; if (minutes >= 60) return -1; break; default: return -1; } if ((seconds >= 60) || (ms >= 1000)) return -1; *time = (((hours * 60) + minutes) * 60 + seconds) * 1000 + ms; return 0; } static void format_time(unsigned long time, char *str, unsigned int len) { unsigned long ms = time % 1000; time /= 1000; unsigned long secs = time % 60; time /= 60; unsigned long minutes = time; time /= 60; unsigned long hours = time; snprintf(str, len, "%.2lu:%.2lu:%.2lu+%.3lu", hours, minutes, secs, ms); } typedef struct mp3cut_s { char filename[256]; unsigned long from, to; } mp3cut_t; typedef struct mp3cut_id3_s { char artist[256]; char title[256]; char album[256]; } mp3cut_id3_t; static unsigned int parse_arguments(mp3cut_t *mp3cuts, unsigned int max_cuts, char *outfilename, unsigned int max_outfilename, mp3cut_id3_t *id3, int argc, char *argv[]) { int i; unsigned int mp3cuts_cnt = 0; memset(id3->title, 0, sizeof(id3->title)); memset(id3->album, 0, sizeof(id3->album)); memset(id3->artist, 0, sizeof(id3->artist)); for (i = 0; i < max_cuts; i++) { mp3cuts[i].from = mp3cuts[i].to = 0; memset(mp3cuts[i].filename, '\0', sizeof(mp3cuts[0].filename)); } for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-h")) { goto exit_usage; } else if (!strcmp(argv[i], "-o")) { if ((i == 1) && (argc > (i+1))) { strncpy(outfilename, argv[i+1], max_outfilename); outfilename[max_outfilename - 1] = '\0'; i++; } else { goto exit_usage; } } else if (!strcmp(argv[i], "-T")) { if (argc > (i+1)) { strncpy(id3->title, argv[i+1], sizeof(id3->title)); id3->title[sizeof(id3->title) - 1] = '\0'; } else { goto exit_usage; } i++; } else if (!strcmp(argv[i], "-N")) { if (argc > (i+1)) { strncpy(id3->album, argv[i+1], sizeof(id3->album)); id3->album[sizeof(id3->album) - 1] = '\0'; } i++; } else if (!strcmp(argv[i], "-A")) { if (argc > (i+1)) { strncpy(id3->artist, argv[i+1], sizeof(id3->artist)); id3->artist[sizeof(id3->artist) - 1] = '\0'; } i++; } else if (!strcmp(argv[i], "-t")) { if (argc > (i+1)) { unsigned char *fromstr, *tostr; fromstr = strtok(argv[i+1], "-"); tostr = strtok(NULL, "-"); if (!fromstr && !tostr) goto exit_usage; if (fromstr && (strlen(fromstr) > 0)) { if (parse_time(fromstr, &mp3cuts[mp3cuts_cnt].from) < 0) { goto exit_usage; } } else { mp3cuts[mp3cuts_cnt].from = 0; } if (tostr && (strlen(tostr) > 0)) { if (parse_time(tostr, &mp3cuts[mp3cuts_cnt].to) < 0) { goto exit_usage; } } else { mp3cuts[mp3cuts_cnt].to = 0; } } i++; } else { if (mp3cuts_cnt >= max_cuts) { fprintf(stderr, "mp3cut cannot handle more than %d cuts\n", max_cuts); return -1; } strncpy(mp3cuts[mp3cuts_cnt].filename, argv[i], sizeof(mp3cuts[0].filename)); mp3cuts[mp3cuts_cnt].filename[sizeof(mp3cuts[0].filename) - 1] = '\0'; mp3cuts_cnt++; } } if (mp3cuts_cnt == 0) goto exit_usage; return mp3cuts_cnt; exit_usage: usage(); return 0; } int main(int argc, char *argv[]) { int retval = EXIT_SUCCESS; char outfilename[256]; mp3cut_t mp3cuts[256]; unsigned int mp3cuts_cnt = 0; mp3cut_id3_t id3; memset(outfilename, '\0', sizeof(outfilename)); mp3cuts_cnt = parse_arguments(mp3cuts, 256, outfilename, sizeof(outfilename), &id3, argc, argv); if (mp3cuts_cnt <= 0) { retval = EXIT_FAILURE; goto exit; } if (strlen(outfilename) == 0) { char *mp3filename = mp3cuts[0].filename; char *basename = strrchr(mp3filename, '/'); if (basename) mp3filename = basename + 1; char *dot = strrchr(mp3filename, '.'); char buf[256]; unsigned int len = dot ? (dot - mp3filename) : strlen(mp3filename); len = min(len + 1, sizeof(buf)); strncpy(buf, mp3filename, len); buf[len - 1] = '\0'; snprintf(outfilename, sizeof(outfilename), "%s.out%s", buf, dot ? dot : ".mp3"); } /* initialize the output stream */ aq_t qout; aq_init(&qout); file_t outfile; if (!file_open_write(&outfile, outfilename)) { fprintf(stderr, "Could not open mp3 file: %s\n", outfilename); retval = EXIT_FAILURE; goto exit; } if (!id3_write_tag(&outfile, id3.album, id3.artist, id3.title, 0, "Created by mp3cut (http://bl0rg.net/software/poc/)")) { fprintf(stderr, "Could not write id3 tag to file: %s\n", outfilename); file_close(&outfile); retval = EXIT_FAILURE; goto exit; } printf("Writing to %s\n", outfilename); /* cycle through the mp3cuts */ int i; for (i = 0; i < mp3cuts_cnt; i++) { file_t mp3file; if (!file_open_read(&mp3file, mp3cuts[i].filename)) { fprintf(stderr, "Could not open mp3 file: %s\n", mp3cuts[i].filename); retval = EXIT_FAILURE; file_close(&outfile); aq_destroy(&qout); goto exit; } char fromstr[256], tostr[256]; format_time(mp3cuts[i].from, fromstr, sizeof(fromstr)); format_time(mp3cuts[i].to, tostr, sizeof(tostr)); printf("Extracting %s-%s from %s\n", fromstr, tostr, mp3cuts[i].filename); aq_t qin; aq_init(&qin); unsigned long long current = 0; int finished = 0; while (!finished) { if (mp3cuts[i].to && ((current / 1000) >= mp3cuts[i].to)) { finished = 1; break; } mp3_frame_t frame; int ret; if ((ret = mp3_next_frame(&mp3file, &frame)) > 0) { if (aq_add_frame(&qin, &frame)) { adu_t *adu = aq_get_adu(&qin); assert(adu != NULL); if ((current / 1000) >= mp3cuts[i].from) { char curstr[256]; format_time(current / 1000, curstr, sizeof(curstr)); if (aq_add_adu(&qout, adu)) { mp3_frame_t *frame_out = aq_get_frame(&qout); assert(frame_out != NULL); memset(frame_out->raw, 0, 4 + frame_out->si_size); if (!mp3_fill_hdr(frame_out) || !mp3_fill_si(frame_out) || (mp3_write_frame(&outfile, frame_out) <= 0)) { fprintf(stderr, "Could not write frame\n"); file_close(&mp3file); file_close(&outfile); retval = 1; goto exit; } free(frame_out); } } current += adu->usec; free(adu); } else { /* ignore error */ } } else { finished = 1; if (ret != EEOF) { fprintf(stderr, "Error reading from %s: %d\n", mp3cuts[i].filename, ret); } else { if ((current / 1000) <= mp3cuts[i].from) { fprintf(stderr, "Could not extract data from %s, file too short\n", mp3cuts[i].filename); } else { if (mp3cuts[i].to == 0) continue; char timebuf[256]; unsigned long duration = (current / 1000) - mp3cuts[i].from; format_time(duration, timebuf, sizeof(timebuf)); fprintf(stderr, "Could only extract %s from %s, file too short\n", timebuf, mp3cuts[i].filename); } } } } file_close(&mp3file); aq_destroy(&qin); } file_close(&outfile); aq_destroy(&qout); fprintf(stderr, "%s written\n", outfilename); exit: return retval; } poc-0.4.2/mp3-read.c0000664000175000001440000006323310210123147014512 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include "mp3.h" #include "bv.h" /*@-boolops@*/ /*M \emph{Read the MP3 frame side information.} **/ int mp3_read_si(mp3_frame_t *frame) { assert(frame != NULL); assert((frame->si_bitsize != 0) || "Trying to read an empty sideinfo"); unsigned char *ptr = frame->raw + 4; /* skip header */ if (/*@-type@*/ frame->protected == 0) ptr += 2; bv_t bv; bv_init(&bv, ptr, frame->si_bitsize); /* reset granule content length */ frame->si.channel[0].granule[0].part2_3_length = 0; frame->si.channel[0].granule[1].part2_3_length = 0; frame->si.channel[1].granule[0].part2_3_length = 0; frame->si.channel[1].granule[1].part2_3_length = 0; mp3_si_t *si = &frame->si; /* stereo or mono */ unsigned int nch = (frame->mode != 3) ? 2 : 1; frame->adu_bitsize = 0; /*M \emph{End of main data.} (ISO) The value of main data end is used to determine the location in the bitstream of the last bit of main data for the frame. The main data end value specifies the location as a negative offset in bytes from the next frame's frame header location in the main data portion of the bitstream **/ si->main_data_end = bv_get_bits(&bv, 9); /*M \emph{Private bits,} (ISO) Bits for private use. These bits will not be used in the future by ISO **/ si->private_bits = nch == 2 ? bv_get_bits(&bv, 3) : bv_get_bits(&bv, 5); /*M \emph{Scalefactor selection information.} (ISO) In Layer III the scalefactor selection information works similarly to Layers I and II. The main difference is the use of the variable scfsi band to apply scfsi to groups of scalefactors instead of single scalefactors. scfsi controls the use of scalefactors to the granules. \begin{itemize} \item '0' - scalefactors are transmitted for each granule \item '1' - scalefactors transmitted for granule 0 are also valid for granule 1 \end{itemize} If short windows are switched on, i.e. block type == 2 for one of the granules, then scfsi is always 0 for this frame. **/ unsigned int i; for (i = 0; i < nch; i++) { unsigned int band; for (band = 0; band < 4; band++) si->channel[i].scfsi[band] = bv_get_bits(&bv, 1); } unsigned int gri; for (gri = 0; gri < 2; gri++) { for (i = 0; i < nch; i++) { mp3_granule_t *gr = &si->channel[i].granule[gri]; /*M \emph{Length of main data.} (ISO) This value contains the number of main data bits used for scalefactors and Huffman code data. Because the length of the side inforamtion is always the same, this value can be used to calculate the beginning of the main inforamtion for each granule and the position of ancillary information (is used). **/ gr->part2_3_length = bv_get_bits(&bv, 12); /* sum the granule main data lengths into the adu size */ frame->adu_bitsize += gr->part2_3_length; /*M \emph{Length of ``big'' Huffman data.} (ISO) The spectral values of each granule are coded with different Huffman code tables. The full frequency ranges from zero to the Nyquist frequency is divided into several regions, which then are coded using different tables. Partitioning is done according to the maximum quantized values. This is done with the assumption that values at higher frequencies are expected to have lower amplitudes or don't need to be coded at all. Starting at high frequencies, the pairs of quantized values equal to zero are counted. This number is named "rzero". Then, quadruples of quantized values with absolute value not exceeding 1 (i.e. only 3 possible quantization levels) are counted. This number is named "count1". Again an even number of values remains. Finally, the number of pairs of values in the region of the spectrum which extends down to zero is named "big values". The maximum absolute value in this range is constrained to 8191. The figure shows the partitioning: \begin{verbatim} xxxxxxxxxxxxx------------------0000000000000000000000000000 | | | | 1 bigvalues*2 bigvalues*2+count1*4 \end{verbatim} The values 000 are all zero. The values --- are -1, 0 or +1. Their number is a multiple of 4. The values xxx are not bound. Iblen is 576. **/ gr->big_values = bv_get_bits(&bv, 9); assert((gr->big_values <= 288) || "big_values are too large"); /*M \emph{Global gain.} (ISO) The quantizer step size information is transmitted in the side information variable global gain. It is logarithmically quantized. For the application of global gain, refer to the formula in 2.4.3.4 "Formula for requantization and all scaling". **/ gr->global_gain = bv_get_bits(&bv, 8); /*M \emph{Scalefactor compression.} (ISO) Selects the number of bits used for the transmission of the scalefactors according to the following table: if block type is 0, 1, or 3: \begin{itemize} \item slen1 : length of scalefactors for the scalefactor bands 0 to 10 \item slen2 : length of scalefactors for the scalefactor bands 11 to 20 \end{itemize} if block type is 2 and switch point is 0: \begin{itemize} \item slen1 : length of scalefactors for the scalefactor bands 0 to 5 \item slen2 : length of scalefactors for the scalefactor bands 6 to 11 \end{itemize} if block type is 2 and switch point is 1: \begin{itemize} \item slen1 : length of scalefactors for the scalefactor bands 0 to 7 (long window scalefactor band) and 4 to 5 (short scalefactor band). Note: scalefactor bands 0-7 are from the "long window scalefactor band" table, and scalefactor bands 4-11 from the "short window scalefactor bands" table. This combination of partitions is contiguous and spans the entire frequency spectrum. \item slen2 : length of scalefactors for the scalefactor bands 6 to 11 \end{itemize} \begin{tabular}{|l|l|l|} \hline scale comp & slen1 & slen2 \\ \hline 0 & 0 & 0 \\ 1 & 0 & 1 \\ 2 & 0 & 2 \\ 3 & 0 & 3 \\ 4 & 3 & 0 \\ 5 & 1 & 1 \\ 6 & 1 & 2 \\ 7 & 1 & 3 \\ 8 & 2 & 1 \\ 9 & 2 & 2 \\ 10 & 2 & 3 \\ 11 & 3 & 1 \\ 12 & 3 & 2 \\ 13 & 3 & 3 \\ 14 & 4 & 2 \\ 15 & 4 & 3 \\ \hline \end{tabular} **/ gr->scale_comp = bv_get_bits(&bv, 4); /*M \emph{Block windowing split flag.} (ISO) Signals that the block uses an other than normal (type 0) window. If blocksplit flag is set, several other variables are set by default: \begin{itemize} \item region address1 = 8 (in case of block type == 1 or block type == 3) \item region address1 = 9 (in case of block type == 2) \item region address2 = 0 In this case the length of region 2 is zero \end{itemize} If blocksplit flag is not set, then the value of block type is zero. **/ gr->blocksplit_flag = bv_get_bits(&bv, 1); if (gr->blocksplit_flag != 0) { /*M \emph{Windowing type.} (ISO) Indicates the window type for the actual granule (see description of the filterbank, Layer III). \begin{itemize} \item type 0 - reserved \item type 1 - start block \item type 2 - 3 short windows \item type 3 - end block \end{itemize} Block type and switch point give the information about assembling of values in the block and about length and count of the transforms. In the case of block type == 2, the switch point indicates whether some polyphase filter subbands are coded using long transforms even in case of block type 2. The polyphase filterbank is described in the clause 2.4.3.2 of Layer I. In the case of long block (block type not equal to 2 or in the lower subbands of block type 2) the IMDCT generates an output of 36 values every 18 input values. The output is windowed depending on the block type and the first half is overlapped with the second half of the block before. The resulting vector is the input of the synthesis part of the polyphase filterbank of one band. In the case of short blocks (in the upper subbands of a type 2 block) three transforms are performed producing 12 output values each. The three vectors are windowed and overlapped each. Concatenating 6 zeros on both ends of the resulting vector gives a vector of length 36, which is processed like the output of a long transform. **/ gr->block_type = bv_get_bits(&bv, 2); /* if block type is reserved we have a wrong frame */ if (gr->block_type == 0) { fprintf(stderr, "Frame has reserved windowing type, skipping...\n"); return 0; } /*M \emph{Switch point.} (ISO) Signals the split point of short/long transforms. The following table shows the number of the scalefactor band above which window switching (i.e. block type different from 0 is used. \begin{tabular}{|l|l|l|} \hline switch point & switch point 1 & switch point s \\ & (No of sb) & (No of sb) \\ \hline 0 & 0 & 0 \\ \hline \multicolumn{3}{|c|}{; switching of the whole spectrum} \\ \hline 1 & 8 & 3 \\ \hline \multicolumn{3}{|c|}{; switching of higher frequencies only} \\ \hline \end{tabular} \begin{description} \item[switching point 1]: Number of scalefactor band (long block scalefactor band) from which point on window switching is used \item[switching point s]: Number of scalefactor band (short block scalefactor band) from which point on window switching is used. \end{description} **/ gr->switch_point = bv_get_bits(&bv, 1); /*M \emph{Huffman code table selection.} (ISO) Different Huffman code tables are used depending on the maximum quantized value and the local statistics of the signal. There are a total of 32 possible tables given in 3-Annex B Table 3-B.7. **/ gr->tbl_sel[0] = bv_get_bits(&bv, 5); gr->tbl_sel[1] = bv_get_bits(&bv, 5); gr->tbl_sel[2] = 0; /*M \emph{Subblock gain offset.} (ISO) Indicates the gain offset (quantization: factor 4) from the global gain for one subblock. Used only with block type 2 (short windows). The values of the subblock have to be divided by $4.^{\textrm{subblock gain(window)}}$ in the decoder. **/ unsigned int j; for (j = 0; j < 3; j++) gr->sub_gain[j] = bv_get_bits(&bv, 3); /* implicitly set */ if (gr->block_type == 2) gr->reg0_cnt = 9; else gr->reg0_cnt = 8; gr->reg1_cnt = 0; } else { unsigned int j; for (j = 0; j < 3; j++) gr->tbl_sel[j] = bv_get_bits(&bv, 5); /*M \emph{First region subdivision information.} (ISO) A further partitioning of the spectrum is used to enhance the performance of the Huffman coder. It is a subdivision of the region which is described by big values. The purpose of this subdivision is to get better error robustness and better coding efficiency. Three regions are used. Each region is coded using a different Huffman code table depending on the maximum quantized value and the loval signal statistics. The values region address[1,2] are used to point to the boundaries of the regions. The region boundaries are aligned with the partitioning of the spectrum into critical bands. In case of block type == 2 (short blocks) the scalefactor bands representing the different time slots are counted separately. If switch point == 0, the total amount of scalefactor bands for the granule in this case is $12 * 3 = 36$. If block type == 2 and switch point == 1, the amount of scalefactor bands is $8 + 9 * 3 = 35$. region address1 counts the number of scalefactor bands until the upper edge of the first region: \begin{tabular}{|l|l|} \hline region address1 & upper edge of region is upper edge of scalefactor band number \\ \hline 0 & 0 (no first region) \\ 1 & 1 \\ 2 & 2 \\ ... & ... \\ 15 & 15 \\ \hline \end{tabular} **/ gr->reg0_cnt = bv_get_bits(&bv, 4); /*M \emph{Second region subdivision information.} (ISO) Region address2 counts the number of scalefactor bands which are partially or totally in region 3. Again if block type == 2 the scalefactor bands representing different time slots are counted separately. **/ gr->reg1_cnt = bv_get_bits(&bv, 3); /* implicitly set */ gr->block_type = 0; gr->switch_point = 0; } /*M \emph{Additional high frequency amplification flag.} (ISO) This is a shortcut for additional high frequency amplification of the quantized values. If preflag is set, the values of a table are added to the scalefactors (see 3-Annex B, Table 3-B.6). This is equivalent to multiplication of the requantized scalefactors with tables values. preflag is never used if block type == 2 (short blocks). **/ gr->preflag = bv_get_bits(&bv, 1); /*M \emph{Scalefactor scale step size.} (ISO) The scalefactors are logarithmically quantized with a step size of 2 (or sqrt(2)) depending on scalefac scale scalefac scale = 0 stepsize sqrt(2) scalefac scale = 1 stepsize 2 **/ gr->scale_scale = bv_get_bits(&bv, 1); /*M (ISO) This flag selects one of two possible Huffman code tables for the region of quadruples of quantized values with magnitude not exceeding 1. \begin{itemize} \item count1table select = 0 Table A of 3-Annex B.7 \item count1table select = 1 Table B of 3-Annex B.7 \end{itemize} **/ gr->cnt1tbl_sel = bv_get_bits(&bv, 1); /*M \emph{Scalefactor length compression table} Table to get scalefactor length information from scale comp. */ static const int slen_table[2][16] = { { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 }, { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 } }; /*M \emph{Scalefactor length} Calculate the bitlength of the scalefactors. **/ gr->slen0 = slen_table[0][gr->scale_comp]; gr->slen1 = slen_table[1][gr->scale_comp]; /*M \emph{Scalefactor total size} Calculate the total size of the scalefactor information for the granule. **/ if (gr->block_type == 2) { if (gr->switch_point != 0) gr->part2_length = 17 * gr->slen0 + 18 * gr->slen1; else gr->part2_length = 18 * gr->slen0 + 18 * gr->slen1; } else { gr->part2_length = 11 * gr->slen0 + 10 * gr->slen1; } gr->part3_length = gr->part2_3_length - gr->part2_length; } } frame->adu_size = (frame->adu_bitsize + 7) / 8; return 1; } /*M \emph{Read the MP3 frame header.} **/ int mp3_read_hdr(mp3_frame_t *frame) { assert(frame != NULL); bv_t bv; bv_init(&bv, frame->raw, 4 * 8); /*M \emph{Header identifaction string.} (ISO) The bit string ``\verb|1111 1111 1111|'' **/ if (bv_get_bits(&bv, 12) != 0xFFF) return 0; /*M \emph{Algorithm ID.} (ISO) one bit to indicate the ID of the algorithm. Equals ``1'' for MPEG audio, ``0'' is reserved **/ frame->id = bv_get_bits(&bv, 1); if (frame->id == 0) return 0; /*M \emph{Layer information.} (ISO) 2 bits to indicate which layer is used, according to the following table \begin{tabular}{|l|l|} \hline 11 & Layer I \\ 10 & Layer II \\ 01 & Layer III \\ 00 & reserved \\ \hline \end{tabular} **/ frame->layer = bv_get_bits(&bv, 2); /* we can only handle Layer III */ if (frame->layer != 1) return 0; /*M \emph{Redundancy protection flag.} (ISO) One bit to indicate whether redundancy has been added in the audio bitstream to facilitate error detection and concealment. Equals 1 if no redundancy has been added, 0 if redundancy has been added. **/ frame->protected = bv_get_bits(&bv, 1); /*M \emph{Bitrate information.} (ISO) Indicates the bitrate. The all zero value indicates the free format condition, in which a fixed bitrate which does not need to be in the list can be used. Fixed means that a frame contains either N or N+1 slots, depending on the value of the padding bit. The bit rate index is an index to a table, which is different for the different Layers. The bit rate index indicates the total bitrate irrespective of the mode (stereo, joint stereo, dual channel, single channel). For Layer II, not all combinations of total bitrate and mode are allowed. See 3-Annex B, Table 3-B.2 "Layer II BIT ALLOCATION TABLES" \begin{tabular}{|l|l|l|l|} \hline bit rate index & Layer I & Layer II & Layer III \\ \hline 0000 & free format & free format & free format \\ 0001 & 32 kbps & 32 kbps & 32 kbps \\ 0010 & 64 kbps & 48 kbps & 40 kbps \\ 0011 & 96 kbps & 56 kbps & 48 kbps \\ 0100 & 128 kbps & 64 kbps & 56 kbps \\ 0101 & 160 kbps & 80 kbps & 64 kbps \\ 0110 & 192 kbps & 96 kbps & 80 kbps \\ 0111 & 224 kbps & 112 kbps & 96 kbps \\ 1000 & 256 kbps & 128 kbps & 112 kbps \\ 1001 & 288 kbps & 160 kbps & 128 kbps \\ 1010 & 320 kbps & 192 kbps & 160 kbps \\ 1011 & 352 kbps & 224 kbps & 192 kbps \\ 1100 & 384 kbps & 256 kbps & 224 kbps \\ 1110 & 416 kbps & 320 kbps & 256 kbps \\ 1111 & 448 kbps & 384 kbps & 320 kbps \\ \hline \end{tabular} In order to provide the smallest possible delay and complexity, the decoder is not required to support a continuously variable bitrate when in Layer I or II. Layer III supports variable bitrate by switching the bit rate index. However, in free format, fixed bitrate is required. **/ frame->bitrate_index = bv_get_bits(&bv, 4); /*M \emph{Sampling frequency information.} (ISO) Indicates the sampling frequency, according to the following table: \begin{tabular}{|l|l|} \hline 00 & 44.1 kHz \\ 01 & 48 kHz \\ 10 & 32 kHz \\ 11 & reserved \\ \hline \end{tabular} A reset of the decoder is required to change the sampling rate **/ frame->samplerfindex = bv_get_bits(&bv, 2); /*M \emph{Padding flag.} (ISO) If this bit equals '1' the frame contains an additional slot to adjust the mean bitrate to the sampling frequency, otherwise this bit will be '0'. Padding is only necessary with a sampling frequency of 44.1 kHz. **/ frame->padding_bit = bv_get_bits(&bv, 1); /*M \emph{Private bit.} (ISO) Bit for private use. This bit will not be used in the future by ISO. **/ frame->private_bit = bv_get_bits(&bv, 1); /*M \emph{Stereo encoding mode.} (ISO) Indicates the mode according to the following table. In Layer I and II the joint stereo mode is intensity stereo, in Layer III it is intensity stereo and/or ms stereo \begin{tabular}{|l|l|} \hline 00 & stereo \\ 01 & joint stereo (intensity stereo and/or ms stereo) \\ 10 & dual channel \\ 11 & single channel \\ \hline \end{tabular} **/ frame->mode = bv_get_bits(&bv, 2); /*M \emph{Joint Stereo subband division information.} (ISO) These bits are used in joint stereo mode. In Layer I and II they indicate which subbands are in intensity stereo. All other subbands are coded in stereo. 00 - subbands 4-31 in intensity stereo, bound==4 01 - subbands 8-31 in intensity stereo, bound==8 10 - subbands 12-31 in intensity stereo, bound==12 11 - subbands 16-31 in intensity stereo, bound==16 In Layer III they indicate which type of join stereo coding method is applied. The frequency ranges over which the intensity stereo and ms stereo modes are applied are implicit in the algorithm. For more information see 2.4.3.4. intensio stereo ms stereo 00 off off 01 on off 10 off on 11 on on **/ frame->mode_ext = bv_get_bits(&bv, 2); /*M \emph{Copyright} (ISO) If this bit equals 0 there is no copyright on the coded bitstream, 1 means copyright protected. **/ frame->copyright = bv_get_bits(&bv, 1); /*M \emph{Original flag.} (ISO) This bit equals 0 if the bitstream is a copy, 1 if it is an original. **/ frame->original = bv_get_bits(&bv, 1); /*M \emph{MPEG Audio emphasis.} (ISO) indicates the type of de-emphasis that shall be used. \begin{itemize} \item 00 - no emphasis \item 01 - 50/15 microsec. emphasis \item 10 - reserved \item 11 - CCITT J.17 \end{itemize} **/ frame->emphasis = bv_get_bits(&bv, 2); if (frame->protected == 0) { frame->crc[0] = frame->raw[4]; frame->crc[1] = frame->raw[5]; } mp3_calc_hdr(frame); return 1; } /*M \emph{Skip the ID3v2 tag at the beginning.} **/ int mp3_skip_id3v2(file_t *mp3, mp3_frame_t *frame) { assert(mp3 != NULL); assert(frame != NULL); unsigned char id3v2_hdr[10]; memcpy(id3v2_hdr, frame->raw, 4); if ((id3v2_hdr[0] != 'I') || (id3v2_hdr[1] != 'D') || (id3v2_hdr[2] != '3')) return 0; if (file_read(mp3, id3v2_hdr + 4, 6) != 6) return EEOF; /* parse synchsafe integer */ size_t tag_size = (((id3v2_hdr[6] & 0x7F) << 21) | ((id3v2_hdr[7] & 0x7F) << 14) | ((id3v2_hdr[8] & 0x7F) << 7) | (id3v2_hdr[9] & 0x7F)) + (id3v2_hdr[5] & 0x10 ? 10 : 0); if (!file_seek_fwd(mp3, tag_size)) return 0; return 1; } /*M \emph{Read the next MP3 frame in the MP3 file.} **/ int mp3_next_frame(file_t *mp3, mp3_frame_t *frame) { assert(mp3 != NULL); assert(frame != NULL); unsigned int resync = 0; again: if (resync != 0) { /* read the next byte and build the new header */ frame->raw[0] = frame->raw[1]; frame->raw[1] = frame->raw[2]; frame->raw[2] = frame->raw[3]; if (file_read(mp3, frame->raw + 3, 1) <= 0) return EEOF; } else { if (file_read(mp3, frame->raw, MP3_HDR_SIZE) <= 0) return EEOF; } if ((frame->raw[0] == 0xFF) && (((frame->raw[1] >> 4) & 0xF) == 0xF)) { if (!mp3_read_hdr(frame)) goto resync; else resync = 0; } else if ((frame->raw[0] == 'I') && (frame->raw[1] == 'D') && (frame->raw[2] == '3')) { if (!mp3_skip_id3v2(mp3, frame)) { goto resync; } else { resync = 0; goto again; } } else { goto resync; } if (file_read(mp3, frame->raw + 4, frame->frame_size - 4) <= 0) return EEOF; if (!mp3_read_si(frame)) goto again; return 1; resync: frame->syncskip++; if (resync++ > MP3_MAX_SYNC) { fprintf(stderr, "Max sync exceeded: %d\n", resync); return ESYNC; } else goto again; } /*M %XXX **/ int mp3_unpack(mp3_frame_t *frame) { if (!mp3_read_hdr(frame)) return 0; if (!mp3_read_si(frame)) return 0; return 1; } /*M **/ #ifdef MP3_TEST int main(int argc, char *argv[]) { mp3_file_t file; mp3_frame_t frame; char *f; if (!(f = *++argv)) { fprintf(stderr, "Usage: mp3test mp3file\n"); return 1; } if (!mp3_open_read(&file, f)) { fprintf(stderr, "Could not open mp3 file: %s\n", f); return 1; } while (mp3_next_frame(&file, &frame) > 0) { printf("frame main_data_end %d\n", frame.si.main_data_end); fgetc(stdin); } mp3_close(&file); return 0; } #endif poc-0.4.2/vorbis.h0000664000175000001440000000324210210123147014405 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef VORBIS_H__ #define VORBIS_H__ #include "buf.h" #include "file.h" #include "ogg.h" #define VORBIS_HDR_SIZE 7 #define VORBIS_SYNC_HDR_BYTE1 ('v') #define VORBIS_SYNC_HDR_BYTE2 ('o') #define VORBIS_SYNC_HDR_BYTE3 ('r') #define VORBIS_SYNC_HDR_BYTE4 ('b') #define VORBIS_SYNC_HDR_BYTE5 ('i') #define VORBIS_SYNC_HDR_BYTE6 ('s') #define VORBIS_ID_HDR_SIZE 30 #define VORBIS_MAX_HDR_PAGES 10 /* actually we don't care about vorbis data */ #if 0 typedef struct vorbis_comment_hdr_s { buf_t raw; } vorbis_comment_hdr_t; /* 0: packet type (id header: 1, comment header: 3, setup header: 5, even number: audio packet) 1, 2, 3, 4, 5, 6: 'vorbis' */ typedef struct vorbis_setup_hdr_s { buf_t raw; } vorbis_setup_hdr_t; #endif typedef struct vorbis_stream_s { /* OGG pages containing the Vorbis headers, so we don't have to create them afterwards for HTTP streaming */ int hdr_pages_cnt; ogg_page_t hdr_pages[VORBIS_MAX_HDR_PAGES]; buf_t id_hdr; buf_t comment_hdr; buf_t setup_hdr; /*M Identification header data. **/ unsigned long vorbis_version; unsigned char audio_channels; unsigned long audio_sample_rate; unsigned long bitrate_maximum; unsigned long bitrate_nominal; unsigned long bitrate_minimum; unsigned char blocksize_0; unsigned char blocksize_1; file_t file; ogg_page_t page; unsigned char segment; } vorbis_stream_t; void vorbis_stream_init(vorbis_stream_t *vorbis); void vorbis_stream_destroy(vorbis_stream_t *vorbis); int vorbis_check_packet(buf_t *buf, unsigned char type); int vorbis_stream_read_hdrs(vorbis_stream_t *vorbis); #endif /* VORBIS_H__ */ /*C **/ poc-0.4.2/pob-fec.c0000664000175000001440000002063710214014115014414 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include #ifdef NEED_GETOPT_H__ #include #endif /* NEED_GETOPT_H__ */ #include "fec-pkt.h" #include "aq.h" #include "fec.h" #include "network.h" #include "fec-group.h" #include "fec-rb.h" #include "pob-fec.h" #define FEC_MINSLEEP 20000 /* 200 ms */ /*M \emph{Structure to hold client accounting information.} This is used to count the number of wrong packets, duplicate packets, out of order packets. **/ typedef struct pob_stat_s { /*M Number of packets received. **/ unsigned int rcvd_pkts; /*M Number of duplicated packets received. **/ unsigned int lost_pkts; /*M Number of bad packets received. **/ unsigned int bad_pkts; /*M Number of incomplete groups received. **/ unsigned int incomplete_groups; } pob_stat_t; static pob_stat_t pob_stats = { 0, 0, 0, 0 }; /*M \emph{Maximal buffer queue size (in packets).} **/ static unsigned short buffer_size = 16; /* - Receive FEC packets, sort them into current group structure - when group complete, decode group into adus and throw them into adu_queue - if older group packet arrives, discard - if newer group packet arrives, ??? - */ /*M \emph{Timestamp of last played group.} **/ static unsigned long tstamp_last = 0; int pob_insert_pkt(fec_pkt_t *pkt) { assert(pkt != NULL); /*M We have received a packet. **/ pob_stats.rcvd_pkts++; int num = 0; /* insert packet into ringbuffer */ if (fec_rb_length() > 0) { /* get index of first packet */ fec_group_t *first_group = fec_rb_first(); assert(first_group != NULL); assert(first_group->buf != NULL); num = net_seqnum_diff(first_group->seq, pkt->hdr.group_seq, 1 << 8); } if (!fec_rb_insert_pkt(pkt, num)) { #ifdef DEBUG fprintf(stderr, "ring buffer full\n"); #endif fec_rb_clear(); tstamp_last = pkt->hdr.group_tstamp; return pob_insert_pkt(pkt); } else { return 1; } } int pob_fec_recv_pkt(int sock, fec_pkt_t *pkt) { /*M Timeout in order to flush next frame to player. **/ struct timeval t_out; t_out.tv_sec = 0; t_out.tv_usec = FEC_MINSLEEP; /*M Listen on receiving socket. **/ fd_set fds; FD_ZERO(&fds); FD_SET(sock, &fds); /*M Wait for network input or for timeout. **/ int ret = select(sock + 1, &fds, NULL, NULL, &t_out); /*M Check for interrupted system call. **/ if (ret == -1) { if ((errno == EINTR) || (errno == EAGAIN)) { return 0; /* timeout */ } else { return -1; /* error */ } } /*M If there is network input, read incoming packet. **/ if (FD_ISSET(sock, &fds)) { fec_pkt_init(pkt); if (fec_pkt_read(pkt, sock) <= 0) { return -1; } else { return 1; } } return 0; } /*M \emph{Simple FEC streaming client main loop.} The mainloop calls the prebuffering routine each time the frame queue is empty, then receives the packets, sorts them into groups, decodes the groups and converts the ADUs into frames. **/ int pob_mainloop(int sock, int quiet) { int retval = 0; /*M Initialize the ADU queue; **/ aq_t frame_queue; aq_init(&frame_queue); fec_pkt_t pkt; int finished = 0; while (!finished) { static int prebuffering = 0; if (fec_rb_cnt == 0) { prebuffering = 1; } switch (pob_fec_recv_pkt(sock, &pkt)) { case -1: finished = 1; retval = -1; continue; case 0: break; default: /*M Insert the packet into the FEC buffer. **/ if (!pob_insert_pkt(&pkt)) { finished = 1; retval = -1; goto exit; } } static unsigned long time_last; unsigned long time_now; /*M Get the current time to see which packets have to be written to standard out. **/ struct timeval tv; gettimeofday(&tv, NULL); time_now = tv.tv_sec * 1000000 + tv.tv_usec; if (prebuffering == 1) { if (fec_rb_cnt >= (fec_rb_size / 2)) { fec_group_t *first_group = fec_rb_first(); assert(first_group != NULL); assert(first_group->buf != NULL); tstamp_last = first_group->tstamp; time_last = time_now; prebuffering = 0; if (!quiet) fprintf(stderr, "\n"); } else { /*M Print prebuffering information. **/ if (!quiet) fprintf(stderr, "Prebuffering: %.2f%%\r", (float)fec_rb_cnt / (fec_rb_size / 2.0) * 100.0); continue; } } /*M Print client information. **/ if (!quiet) { static int count = 0; if ((count++ % 10) == 0) { fprintf(stderr, "pkts: %.8u\tdrop: %.6u\tincomplete: %.6u\tbuf: %.6u len:%.4u\t\r", pob_stats.rcvd_pkts, pob_stats.lost_pkts, pob_stats.incomplete_groups, fec_rb_cnt, fec_rb_length()); } } #ifdef DEBUG fec_rb_print(); #endif unsigned long tstamp_now = tstamp_last + (time_now - time_last); while (fec_rb_length() > 0) { fec_group_t *group = fec_rb_first(); assert(group != NULL); if (group->buf != NULL) { /* boeser hack XXX */ if (group->tstamp > (tstamp_now + 3000)) break; /* decode group into adu queue */ if (!fec_group_decode_to_adus(group, &frame_queue)) { fprintf(stderr, "Could not decode group\n"); /* XXX really continue? */ } pob_stats.lost_pkts += group->fec_n - group->rcvd_pkts; if (group->rcvd_pkts < group->fec_k) pob_stats.incomplete_groups++; mp3_frame_t *frame; while ((frame = aq_get_frame(&frame_queue)) != NULL) { memset(frame->raw, 0, 4 + frame->si_size); /*M Write packet payload. **/ if (!mp3_fill_hdr(frame) || !mp3_fill_si(frame) || (write(STDOUT_FILENO, frame->raw, frame->frame_size) < (int)frame->frame_size)) { fprintf(stderr, "Error writing to stdout\n"); free(frame); retval = 0; goto exit; } free(frame); } tstamp_last = tstamp_now; time_last = time_now; } fec_rb_pop(); } } exit: /*M Destroy the ADU queue. **/ aq_destroy(&frame_queue); return retval; } /*M \emph{Print FEC client usage.} **/ static void usage(void) { fprintf(stderr, "Usage: ./pob [-s address] [-p port] [-b size] [-q]\n"); fprintf(stderr, "\t-s address : destination address (default 0.0.0.0)\n"); fprintf(stderr, "\t-p port : destination port (default 1500)\n"); fprintf(stderr, "\t-b size : maximal number of fec groups in buffer (default 16)\n"); fprintf(stderr, "\t-q : quiet\n"); } /*M \emph{FEC RTP client entry routine.} **/ int main(int argc, char *argv[]) { char *address = NULL; unsigned short port = 1500; int retval = EXIT_SUCCESS, quiet = 0; /*M Process the command line arguments. **/ int c; while ((c = getopt(argc, argv, "hs:p:b:t:q")) >= 0) { switch (c) { case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = atoi(optarg); break; case 'b': buffer_size = (unsigned short)atoi(optarg); break; case 'q': quiet = 1; break; case 'h': default: usage(); retval = EXIT_SUCCESS; goto exit; } } /*M Initialize the ring buffer. **/ fec_rb_init(buffer_size); if (address == NULL) { #ifdef WITH_IPV6 address = strdup("ff02::4"); #else address = strdup("0.0.0.0"); #endif /* WITH_IPV6 */ } /*M Create the receiving socket. **/ int sock; #ifdef WITH_IPV6 sock = net_udp6_recv_socket(address, port); #else sock = net_udp4_recv_socket(address, port); #endif /* WITH_IPV6 */ if (sock < 0) { fprintf(stderr, "Could not open socket\n"); retval = EXIT_FAILURE; goto exit; } if (!pob_mainloop(sock, quiet)) retval = EXIT_FAILURE; if (close(sock) < 0) perror("close"); exit: fec_rb_destroy(); if (address != NULL) free(address); return retval; } /*C **/ poc-0.4.2/pob-fec.h0000664000175000001440000000000110165025647014421 0ustar manuelusers00000000000000 poc-0.4.2/galois.c0000664000175000001440000000656010210123147014360 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net Based on an implementation by Luigi Rizzo **/ #include "galois.h" /*M \emph{Polynomial representation of field elements.} **/ gf gf_polys[256] = { 0 }; /*M \emph{Logarithmic representation of field elements.} **/ gf gf_logs[256] = { 0 }; /*M \emph{Precomputed multiplication table.} **/ gf gf_mul[256][256] = { { 0 } }; /*M \emph{Precomputed inverse table.} **/ gf gf_inv[256] = { 0 }; /*M \emph{A primitive polynomial.} A primitive polynomial for \gf{2^8}, namely \[1 + x^2 + x^3 + x^4 + x^8\] **/ static char gf_prim_poly[] = "101110001"; /*M \emph{Initialize data structures.} **/ void gf_init(void) { /*M Notice that $x^8 = x^4 + x^3 + x^2 + 1$. We will fill up the "eight" power of alpha from the prime polynomial. **/ gf_polys[8] = 0; /*M The first 8 elements are just alpha shifted to the left. **/ int i; gf g = 1; for (i = 0; i < 8; i++, g <<= 1) { gf_polys[i] = g; /*M Remember logarithm by storing it into the logarithm lookup table. **/ gf_logs[gf_polys[i]] = i; /*M Fill up the eighth element. **/ if (gf_prim_poly[i] == '1') gf_polys[8] |= g; } /*M Remember logarithm of eigth element. **/ gf_logs[gf_polys[8]] = 8; /*M For each further element, $a^n = a^(n-1) * a$. We just need to calculate the modulo \verb|gf_prim_poly|, which is of degree $8$. **/ g = 1 << 7; for (i = 9; i < 255; i++) { if (gf_polys[i - 1] >= g) /*M $a^{n-1} * a > $ \verb|gf_prim_poly|, then $a^n = a^{n-1} * a = a^8 + ... = a^4 + a^3 + a^2 + 1$. **/ gf_polys[i] = gf_polys[8] ^ ((gf_polys[i - 1]) << 1); else gf_polys[i] = gf_polys[i - 1] << 1; /*M Remember logarithm. **/ gf_logs[gf_polys[i]] = i; } /*M The 0th element is undefined. **/ gf_logs[0] = 0xFF; /*M Compute multiplication table. **/ for (i = 0; i < 256; i++) { int j; for (j = 0; j < 256; j++) { if ((i == 0) || (j == 0)) gf_mul[i][j] = 0; else gf_mul[i][j] = gf_polys[(gf_logs[i] + gf_logs[j]) % 255]; } for (j = 0; j < 256; j++) gf_mul[0][j] = gf_mul[j][0] = 0; } /*M Compute inverses. **/ gf_inv[0] = 0; gf_inv[1] = 1; for (i = 2; i < 256; i++) gf_inv[i] = gf_polys[255 - gf_logs[i]]; } /*M \emph{Computes addition of a row multiplied by a constant.} Computes $a = a + c * b$, $a, b \in \gf{2^8}^k, c \in \gf{2^8}$. **/ void gf_add_mul(gf *a, gf *b, gf c, int k) { int i; for (i = 0; i < k; i++) a[i] = GF_ADD(a[i], GF_MUL(c, b[i])); } /*C **/ #ifdef GALOIS_TEST #include void testit(char *name, int result, int should) { if (result == should) { printf("Test %s was successful\n", name); } else { printf("Test %s was not successful, %x should have been %x\n", name, result, should); } } int main(void) { gf a, b, c; gf_init(); a = 1; b = 37; c = 78; testit("1 * ( 37 + 78 ) = 1 * 37 + 1 * 78", GF_MUL(a, GF_ADD(b, c)), GF_ADD(GF_MUL(a, b), GF_MUL(a, c))); testit("(1 * 37) * 78 = 1 * (37 * 78)", GF_MUL(GF_MUL(a, b), c), GF_MUL(a, GF_MUL(b, c))); testit("(37 * 78) * 37 = (37 * 37) * 78", GF_MUL(GF_MUL(b, c), b), GF_MUL(GF_MUL(b, b), c)); testit("b * b^-1 = 1", GF_MUL(b, GF_INV(b)), 1); return 0; } #endif /* GALOIS_TEST */ poc-0.4.2/pack.c0000664000175000001440000000423610210123147014016 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include "pack.h" /*@+charint@*/ /*M \emph{Unpack a big endian 16 bit integer.} This could not be done in a macro. **/ unsigned int uint16_unpack__(/*@out@*/ unsigned char **ptr) { int i = (*((*ptr)++) & 0xFF) << 8; return (i |= *((*ptr)++) & 0xFF); } /*M \emph{Unpack a big endian 32 bit integer.} This could not be done in a macro. **/ unsigned int uint32_unpack__(/*@out@*/ unsigned char **ptr) { int i = (*((*ptr)++) & 0xFF) << 24; i |= (*((*ptr)++) & 0xFF) << 16; i |= (*((*ptr)++) & 0xFF) << 8; return (i |= *((*ptr)++) & 0xFF); } /*M \emph{Unpack a little endian 16 bit integer.} This could not be done in a macro. **/ unsigned int le_uint16_unpack__(/*@out@*/ unsigned char **ptr) { int i = (*((*ptr)++) & 0xFF); return (i |= (*((*ptr)++) & 0xFF) << 8); } /*M \emph{Unpack a little endian 32 bit integer.} This could not be done in a macro. **/ unsigned int le_uint32_unpack__(/*@out@*/ unsigned char **ptr) { int i = (*((*ptr)++) & 0xFF); i |= (*((*ptr)++) & 0xFF) << 8; i |= (*((*ptr)++) & 0xFF) << 16; return (i |= (*((*ptr)++) & 0xFF) << 24); } /*C **/ #ifdef PACK_TEST #include void testit(char *name, int result, int should) { if (result == should) { printf("Test %s was successful\n", name); } else { printf("Test %s was not successful, %x should have been %x\n", name, result, should); } } int main(void) { int i16 = 0x1234, i32 = 0x12345678; unsigned char test[4], *ptr; ptr = test; UINT16_PACK(ptr, i16); ptr = test; testit("UNPACK after PACK 16", UINT16_UNPACK(ptr), i16); ptr = test; UINT32_PACK(ptr, i32); ptr = test; testit("UNPACK after PACK 32", UINT32_UNPACK(ptr), i32); ptr = test; UINT16_PACK(ptr, i16); testit("Big Endianness 16 1/2", test[0], 0x12); testit("Big Endianness 16 2/2", test[1], 0x34); ptr = test; UINT32_PACK(ptr, i32); testit("Big Endianness 32 1/4", test[0], 0x12); testit("Big Endianness 32 2/4", test[1], 0x34); testit("Big Endianness 32 3/4", test[2], 0x56); testit("Big Endianness 32 4/4", test[3], 0x78); return 0; } #endif poc-0.4.2/fec-pkt.c0000664000175000001440000000547510211673061014445 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include "pack.h" #include "fec-pkt.h" /*M \emph{Initialize a FEC packet by filling common header fields.} The version field is set to $1$ and the payload length to $0$. **/ void fec_pkt_init(fec_pkt_t *pkt) { assert(pkt != NULL); pkt->hdr.magic = FEC_PKT_MAGIC; pkt->hdr.version = 1; pkt->hdr.len = 0; pkt->hdr.group_seq = 0; pkt->payload = pkt->data + FEC_PKT_HDR_SIZE; } static void fec_pkt_pack(fec_pkt_t *pkt) { assert(pkt != NULL); unsigned char *ptr = pkt->data; /*M Pack the header data into the data buffer. **/ UINT8_PACK(ptr, pkt->hdr.magic); UINT8_PACK(ptr, pkt->hdr.version); UINT8_PACK(ptr, pkt->hdr.group_seq); UINT8_PACK(ptr, pkt->hdr.packet_seq); UINT8_PACK(ptr, pkt->hdr.fec_k); UINT8_PACK(ptr, pkt->hdr.fec_n); UINT16_PACK(ptr, pkt->hdr.fec_len); UINT16_PACK(ptr, pkt->hdr.len); UINT32_PACK(ptr, pkt->hdr.group_tstamp); } /*M \emph{Send a FEC packet to filedescriptor using send.} Fills the packet data buffer with the packed header. Sequence number fields are not incremented, but have to be set by the application. **/ ssize_t fec_pkt_send(fec_pkt_t *pkt, int fd) { assert(pkt != NULL); fec_pkt_pack(pkt); return send(fd, pkt->data, FEC_PKT_HDR_SIZE + pkt->hdr.len, 0); } ssize_t fec_pkt_sendto(fec_pkt_t *pkt, int fd, struct sockaddr *to, socklen_t tolen) { assert(pkt != NULL); fec_pkt_pack(pkt); return sendto(fd, pkt->data, FEC_PKT_HDR_SIZE + pkt->hdr.len, 0, to, tolen); } /*M \emph{Read a FEC packet from filedescriptor.} Reads a FEC packet from the filedescriptor, and unpacks the header fields into the header structure. **/ int fec_pkt_read(fec_pkt_t *pkt, int fd) { assert(pkt != NULL); /*M Read the packet (reading maximum packet size from the UDP socket). **/ ssize_t len; switch (len = read(fd, pkt->data, FEC_PKT_SIZE)) { case 0: /* EOF */ return 0; case -1: /* error */ return -1; default: break; } if (len < FEC_PKT_HDR_SIZE) return -1; /*M Unpack the header data. **/ unsigned char *ptr = pkt->data; pkt->hdr.magic = UINT8_UNPACK(ptr); if (pkt->hdr.magic != FEC_PKT_MAGIC) return -1; pkt->hdr.version = UINT8_UNPACK(ptr); pkt->hdr.group_seq = UINT8_UNPACK(ptr); pkt->hdr.packet_seq = UINT8_UNPACK(ptr); pkt->hdr.fec_k = UINT8_UNPACK(ptr); pkt->hdr.fec_n = UINT8_UNPACK(ptr); pkt->hdr.fec_len = UINT16_UNPACK(ptr); pkt->hdr.len = UINT16_UNPACK(ptr); pkt->hdr.group_tstamp = UINT32_UNPACK(ptr); if (pkt->hdr.len != (len - FEC_PKT_HDR_SIZE)) return -1; /*M Update the payload pointer. **/ pkt->payload = pkt->data + FEC_PKT_HDR_SIZE; return 1; } /*M **/ poc-0.4.2/adu.h0000664000175000001440000000014410165025647013667 0ustar manuelusers00000000000000#ifndef ADU_H__ #define ADU_H__ #include "mp3.h" typedef mp3_frame_t adu_t; #endif /* ADU_H__ */ poc-0.4.2/libfec.c0000664000175000001440000001515710204466440014341 0ustar manuelusers00000000000000#include #include #include #include #include #include #include #include "fec.h" #include "fec-group.h" #include "fec-pkt.h" #include "libfec.h" #define min(a,b) ((a) > (b) ? (b) : (a)) static int initialized = 0; static file_t infile; static int infile_open = 0; static aq_t qin; static file_t outfile; static int outfile_open = 0; static aq_t qout; void libfec_init(char *infilename, char *outfilename) { if (infilename) { aq_init(&qin); if (!file_open_read(&infile, infilename)) assert(NULL); infile_open = 1; } if (outfilename) { aq_init(&qout); if (!file_open_write(&outfile, outfilename)) assert(NULL); outfile_open = 1; } initialized = 1; } void libfec_close(void) { if (infile_open) { aq_destroy(&qin); file_close(&infile); infile_open = 0; } if (outfile_open) { aq_destroy(&qout); file_close(&outfile); outfile_open = 0; } initialized = 0; } int libfec_read_adu(unsigned char *dst, unsigned int len) { assert(dst != NULL); assert(initialized); assert(infile_open); mp3_frame_t frame; while (mp3_next_frame(&infile, &frame) > 0) { if (aq_add_frame(&qin, &frame)) { adu_t *adu = aq_get_adu(&qin); assert(adu != NULL); if (adu->adu_size == 0) { free(adu); continue; } unsigned int retlen = min(len, mp3_frame_size(adu)); memcpy(dst, adu->raw, retlen); free(adu); return retlen; } } return -1; } void libfec_write_adu(unsigned char *buf, unsigned int len) { assert(buf != NULL); assert(initialized); assert(outfile_open); adu_t adu; memcpy(adu.raw, buf, len); int ret = mp3_unpack(&adu); assert(ret); if (aq_add_adu(&qout, &adu)) { mp3_frame_t *frame = aq_get_frame(&qout); assert(frame != NULL); if (!mp3_fill_hdr(frame) || !mp3_fill_si(frame) || !mp3_write_frame(&outfile, frame)) assert(NULL); free(frame); } } fec_decode_t *libfec_new_group(unsigned char fec_k, unsigned char fec_n, unsigned long fec_len) { fec_decode_t *group = malloc(sizeof(fec_decode_t)); if (group == NULL) return NULL; fec_group_init(group, fec_k, fec_n, 0, 0, fec_len); return group; } void libfec_add_pkt(fec_decode_t *group, unsigned char pkt_seq, unsigned long len, unsigned char *data) { assert(group != NULL); assert(data != NULL); assert(len <= group->fec_len); assert(pkt_seq <= group->fec_n); fec_pkt_t pkt; fec_pkt_init(&pkt); pkt.hdr.fec_k = group->fec_k; pkt.hdr.fec_n = group->fec_n; pkt.hdr.group_seq = group->seq; pkt.hdr.packet_seq = pkt_seq; pkt.hdr.len = len; pkt.hdr.fec_len = group->fec_len; pkt.hdr.group_tstamp = group->tstamp; memcpy(pkt.payload, data, len); fec_group_insert_pkt(group, &pkt); } unsigned int libfec_decode(fec_decode_t *group, unsigned char *dst, unsigned int idx, unsigned int len) { assert(initialized); assert(group != NULL); assert(dst != NULL); assert(idx < group->fec_k); if (!group->decoded) fec_group_decode(group); if (group->decoded) { unsigned int retlen; if (group->lengths[idx] > 0) { retlen = min(len, group->lengths[idx]); } else { retlen = min(len, group->fec_len); } memcpy(dst, group->buf + idx * group->fec_len, retlen); return retlen; } else { if (group->lengths[idx] > 0) { unsigned int retlen = min(len, group->lengths[idx]); memcpy(dst, group->buf + idx * group->fec_len, retlen); return retlen; } else { return 0; } } } void libfec_delete_group(fec_decode_t *group) { assert(group != NULL); fec_group_destroy(group); free(group); } struct fec_encode_s { unsigned char fec_k; unsigned char fec_n; fec_t *fec; unsigned char *adus; unsigned int *lengths; unsigned char **adu_ptrs; unsigned char count; unsigned int max_length; }; fec_encode_t *libfec_new_encode(unsigned char fec_k, unsigned char fec_n) { if (fec_k > fec_n) return NULL; fec_encode_t *encode = malloc(sizeof(fec_encode_t)); if (encode == NULL) return NULL; encode->fec_n = fec_n; encode->fec_k = fec_k; encode->adus = NULL; encode->adu_ptrs = NULL; encode->lengths = NULL; encode->count = 0; encode->max_length = 0; encode->fec = fec_new(encode->fec_k, encode->fec_n); if (encode->fec == NULL) goto exit; encode->adus = malloc(FEC_PKT_PAYLOAD_SIZE * fec_k); if (encode->adus == NULL) goto exit; memset(encode->adus, 0, FEC_PKT_PAYLOAD_SIZE * fec_k); encode->adu_ptrs = malloc(encode->fec_k * sizeof(unsigned char *)); if (encode->adu_ptrs == NULL) goto exit; encode->lengths = malloc(sizeof(unsigned int) * fec_k); if (encode->lengths == NULL) goto exit; int i; for (i = 0; i < encode->fec_k; i++) { encode->adu_ptrs[i] = encode->adus + i * FEC_PKT_PAYLOAD_SIZE; encode->lengths[i] = 0; } return encode; exit: libfec_delete_encode(encode); return NULL; } void libfec_delete_encode(fec_encode_t *encode) { assert(encode != NULL); if (encode->adus) free(encode->adus); if (encode->lengths) free(encode->lengths); if (encode->adu_ptrs) free(encode->adu_ptrs); if (encode->fec) fec_free(encode->fec); free(encode); } int libfec_add_adu(fec_encode_t *encode, unsigned long len, unsigned char *data) { assert(encode != NULL); assert(encode->lengths != NULL); assert(data != NULL); if ((encode->adus == NULL) || (encode->count >= encode->fec_k)) return 0; encode->lengths[encode->count] = len; memcpy(encode->adu_ptrs[encode->count], data, len); encode->count++; if (encode->max_length < len) encode->max_length = len; return 1; } unsigned int libfec_max_length(fec_encode_t *encode) { return encode->max_length; } unsigned int libfec_encode(fec_encode_t *encode, unsigned char *dst, unsigned int idx, unsigned int len) { assert(encode != NULL); if (encode->count != encode->fec_k) return 0; if (encode->max_length > len) return 0; assert(encode->adu_ptrs != NULL); assert(encode->fec != NULL); assert(dst != NULL); fec_encode(encode->fec, encode->adu_ptrs, dst, idx, len); if (idx < encode->fec_k) return encode->lengths[idx]; else return encode->max_length; } poc-0.4.2/galois.h0000664000175000001440000001646410210123147014371 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef GALOIS_H__ #define GALOIS_H__ /*H \subsection{Galois field implementation} To avoid roundings using calculations of FEC coefficients, we need to compute in a finite field. \subsubsection{Mathematical background} % Group \begin{definition} A \emph{group} is a set $G$ with a binary operation $\cdot$ satisfying the following axioms: \begin{enumerate} \item \emph{Closure}: $\forall a, b \in G$: $a \cdot b \in G$ \item \emph{Associativity}: $\forall a, b, c \in G$: $\left(a \cdot b\right) \cdot c = a \cdot \left(b \cdot c\right)$ \item \emph{Identity}: $\forall a \in G$: $\exists e \in G$: $e \cdot a = a \cdot e = a$ \item \emph{Inverse}: $\forall a \in G$: $\exists a^{-1} \in G$: $a \cdot a^{-1} = a^{-1} \cdot a = e$ \end{enumerate} \end{definition} % abelian group \begin{definition} A group $G$ is \emph{commutative} or \emph{abelian} if \[\forall a, b \in G: a \cdot b = b \cdot a.\] \end{definition} % subgroup \begin{definition} A \emph{subgroup} of a group $G$ is a subset $H$ of $G$ that is itself a group under the operation of $G$. \end{definition} % ring \begin{definition} A \emph{ring} is a set $R$ with two binary operations, addition $+$ and multiplication $\cdot$, satisfying the following axioms: \begin{enumerate} \item $\left(R, +\right)$ is an abelian group \item \emph{Associativity for multiplication}: $\forall a, b, c \in R$: $\left(a \cdot b\right) \cdot c = a \cdot \left(b \cdot c\right)$ \item \emph{Distributivity}: $\forall a, b, c \in R$: $a \cdot \left(b + c\right) = \left(a \cdot b\right) + \left(a \cdot c\right)$ and $\left(b + c\right) \cdot a = \left(b \cdot a\right) + \left(c \cdot a\right)$ \end{enumerate} \end{definition} % field \begin{definition} A \emph{field} is a set $F$ with two binary operations, addition $+$ and multiplication $\cdot$, satisfying the following axioms: \begin{enumerate} \item $\left(F, +\right)$ is an abelian group \item $\left(F - \left\{0\right\}, \cdot\right)$ is an abelian group \item \emph{Distributivity}: $\forall a, b, c \in F$: $a \cdot \left(b + c\right) = \left(a \cdot b\right) + \left(a \cdot c\right)$ \end{enumerate} \end{definition} % subfield \begin{definition} A \emph{subfield} of a field $F$ is a subset $G$ of $F$ that is itself a field under the operations of $F$. \end{definition} % characteristic \begin{definition} The additive subgroup generated by $1$ (that is, $0, 1, 1+1, 1+1+1, \dots$) has finite order, and its elements are called the \emph{field integers}. This order is called the \emph{characteristic} of a finite field. \end{definition} % characteristic is a prime number \begin{theorem} The characteristic of a finite field is a prime number. \end{theorem} % finite fields have p^m elements \begin{theorem} A finite field has $p^m$ elements, where $p$ is the characteristic of the field. \end{theorem} % multiplicative groups of finite fields are cyclic \begin{theorem} \label{theorem:finite-cyclic} The multiplicative group of the finite field \gf{q} is cyclic of order $q - 1$. \end{theorem} % definition GF(p) \begin{theorem} The integers ($0, 1, \dots, p-1$) with modulo $p$ arithmetic form a commutative ring, in which every nonzero element has a multiplicative inverse, thus forming a field. \end{theorem} \begin{definition} The field of the integers with modulo $p$ arithmetic is called \gf{p}. \end{definition} % definition GF(Q) % definition prime polynomial \begin{definition} A \emph{monic} polynomial is a polynomial with leading coefficient $1$. \end{definition} \begin{definition} An \emph{irreducible} polynomial has no proper divisors (divisors of smaller degree). \end{definition} \begin{definition} A \emph{prime} polynomial is a monic irreducible polynomial. \end{definition} \begin{theorem} The polynomials over a finite field \gf{q} modulo a prime polynomial of degree $m$ form a field with $q^m$ elements. \end{theorem} \begin{definition} The field of the polynomials over a finite field \gf{q} modulo a prime polynomial of degree $m$ form a field called \gf{q^m}. \end{definition} % definition vector space \begin{definition} A \emph{vector space} is a set $V$ of \emph{vectors} over a field $F$ of \emph{scalars} with a binary operator on $V$ and a scalar-vector product $\cdot$ satisfying the following axioms: \begin{enumerate} \item $\left(V, +\right)$ is a commutative group \item $\forall v \in V$: $1 \cdot v = v$ \item \emph{Distributivity}: $\forall a \in F, v_1, v_2 \in V$: $a \cdot \left(v_1 + v_2\right) a \cdot v_1 + a \cdot v_2$ and $\forall a_1, a_2 \in F, v \in V$: $\left(a_1 + a_2\right) \cdot v = a_1 \cdot \left(a_2 \cdot v\right)$ \end{enumerate} \end{definition} \subsubsection{Representation of \gf{p} elements as polynomials} In a finite field $F$ of characteristic $p$, any sum of multiple $p$ ones is $0$, so the arithmetic with field integers is the same as the integers modulo $p$. The field integers are closed under division, and are a subfield of $F$. Furthermore, they are the smallest subfield of $F$, because every field must contain $1$ and all of its sums and products. Thus, $F$ can be considered a vector space over the subfield \gf{p}. However, $F$ has many bases over \gf{p} Efficient multiplication and division can be achieved when choosing a good basis for F over \gf{p}: the powers of an element $\alpha \in F$. If $\left\{1, \alpha, \dots, \alpha^{m-1}\right\}$ is linearly independent, then every element of $F$ is a linear combination of powers of $\alpha$, i.e. a polynomial in $\alpha$ of degree less than $m$. The sum operation is the sum between coefficients, modulo $p$, the product is the product between polynomials, modulo a prime polynomial of degree $m$, and with coefficients reduced modulo $p$. When $p = 2$, operations on \gf{2^m} are extremely simple: an element of \gf{2^m} requires $m$ bits to be represented. Sum and substraction become the same operation, which is simply implemented with an exclusive \verb|OR|. There exists $\alpha \in F$ such that $F$ can be represented as $\left\{0, 1, \alpha, \alpha^2, \dots, \alpha^{p^m-2}\right\}$ (see \ref{theorem:finite-cyclic}). Thus, we can express any non-zero field element as $\alpha^k$, with $k$ being the ``logarithm'', and multiplication and division can be computed using logarithms. \subsection{Code} We restrict ourselves to the implementation of \gf{2^8}. Multiplications are done using lookup, division can be done using logarithm table, substraction and addition is \verb|XOR|. **/ /*M \emph{Galois field element type.} We use polynomials over \gf{8}, so we need 8 bits. **/ typedef unsigned char gf; /*M \emph{Polynomial representation of field elements.} **/ extern gf gf_polys[256]; /*M \emph{Logarithmic representation of field elements.} **/ extern gf gf_logs[256]; /*M \emph{Precomputed multiplication table.} **/ extern gf gf_mul[256][256]; /*M \emph{Precomputed inverse table.} **/ extern gf gf_inv[256]; void gf_init(void); void gf_add_mul(gf *a, gf *b, gf c, int k); #define GF_MUL(x, y) (gf_mul[(x)][(y)]) #define GF_ADD(x, y) ((x) ^ (y)) #define GF_INV(x) (gf_inv[(x)]) /*C **/ #endif /* GALOIS_H__ */ poc-0.4.2/pack.h0000664000175000001440000000714610210123147014026 0ustar manuelusers00000000000000 /*C (c) 2005 bl0rg.net **/ #ifndef PACK_H__ #define PACK_H__ /*M \emph{8 bits value packing macro.} This macro advances the buffer pointer it is given as first argument, and fills the buffer with the 8 bits value given as second argument. **/ #define UINT8_PACK(ptr, i) { *(ptr++) = i; } /*M \emph{8 bits value unpacking macro.} This macro advances the buffer pointer it is given as first argument, and returns the unpacked 8 bits value in the buffer. **/ #define UINT8_UNPACK(ptr) (*(ptr++)) /*M \emph{16 bits value packing macro.} This macro advances the buffer pointer it is given as first argument, and fills the buffer with the big endian packed value given as second argument. **/ #define UINT16_PACK(ptr, i) \ { *(ptr++) = (unsigned char)(((i) >> 8) & 0xFF); \ *(ptr++) = (unsigned char)((i) & 0xFF); } /*M \emph{32 bits value packing macro.} This macro advances the buffer pointer it is given as first argument, and fills the buffer with the big endian packed value given as second argument. **/ #define UINT32_PACK(ptr, i) \ { *(ptr++) = (unsigned char)(((i) >> 24) & 0xFF); \ *(ptr++) = (unsigned char)(((i) >> 16) & 0xFF); \ *(ptr++) = (unsigned char)(((i) >> 8) & 0xFF); \ *(ptr++) = (unsigned char)((i) & 0xFF); } /*M \emph{24 bits value packing macro.} **/ #define UINT24_PACK(ptr, i) \ { *(ptr++) = (unsigned char)(((i) >> 16) & 0xFF); \ *(ptr++) = (unsigned char)(((i) >> 8) & 0xFF); \ *(ptr++) = (unsigned char)((i) & 0xFF); } /*M \emph{16 bits value unpacking macro.} This macro advances the buffer pointer it is given as first argument, and returns the unpacked big endian value in the buffer. **/ #define UINT16_UNPACK(ptr) uint16_unpack__(&ptr) unsigned int uint16_unpack__(/*@out@*/ unsigned char **ptr); /*M \emph{32 bits value unpacking macro.} This macro advances the buffer pointer it is given as first argument, and returns the unpacked big endian value in the buffer. **/ #define UINT32_UNPACK(ptr) uint32_unpack__(&ptr) unsigned int uint32_unpack__(/*@out@*/ unsigned char **ptr); /*M \emph{16 bits value packing macro.} This macro advances the buffer pointer it is given as first argument, and fills the buffer with the little endian packed value given as second argument. **/ #define LE_UINT16_PACK(ptr, i) \ { *(ptr++) = (unsigned char)((i) & 0xFF); \ *(ptr++) = (unsigned char)(((i) >> 8) & 0xFF); } /*M \emph{32 bits value packing macro.} This macro advances the buffer pointer it is given as first argument, and fills the buffer with the little endian packed value given as second argument. **/ #define LE_UINT32_PACK(ptr, i) \ { *(ptr++) = (unsigned char)((i) & 0xFF); \ *(ptr++) = (unsigned char)(((i) >> 8) & 0xFF); \ *(ptr++) = (unsigned char)(((i) >> 16) & 0xFF); \ *(ptr++) = (unsigned char)(((i) >> 24) & 0xFF); } /*M \emph{16 bits value unpacking macro.} This macro advances the buffer pointer it is given as first argument, and returns the unpacked little endian value in the buffer. **/ #define LE_UINT16_UNPACK(ptr) le_uint16_unpack__(&ptr) unsigned int le_uint16_unpack__(/*@out@*/ unsigned char **ptr); /*M \emph{32 bits value unpacking macro.} This macro advances the buffer pointer it is given as first argument, and returns the unpacked little endian value in the buffer. **/ #define LE_UINT32_UNPACK(ptr) le_uint32_unpack__(&ptr) unsigned int le_uint32_unpack__(/*@out@*/ unsigned char **ptr); #endif /* PACK_H__ */ /*C **/ poc-0.4.2/mp3-huffman.c0000664000175000001440000000124510210123147015216 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include "bv.h" #include "mp3.h" int mp3_read_huffman(mp3_frame_t *frame) { assert(frame != NULL); unsigned int granule_offset = 0; unsigned int i; for (i = 0; i < 2; i++) { unsigned int nch = (frame->mode != 3) ? 2 : 1; unsigned int j; for (j = 0; j < nch; j++) { mp3_granule_t *gr = &frame->si.channel[j].granule[i]; granule_offset += gr->part2_length; unsigned int n1 = unsigned int bit0 = granule_offset & 7; bv_t bv; bv_init(&bv, mp3_frame_data_begin(frame) + (granule_offset >> 3), gr->part3_length + bit0); } } poc-0.4.2/libfec.h0000664000175000001440000000535710204462122014340 0ustar manuelusers00000000000000#ifndef LIBFEC_H__ #define LIBFEC_H__ struct fec_group_s; typedef struct fec_group_s fec_decode_t; struct fec_encode_s; typedef struct fec_encode_s fec_encode_t; /* * Initialize the library. Must be called before using any other call * of the library. * * If infile is not NULL, the given file is opened ("-" for * stdin). Further calls to libfec_read_adu() will return the next * adu in the file. * * If outfile is not NULL, the given file is opened ("-" for * stdout). Further calls to libfec_write_adu() will write the given * ADU to the file (after conversion to MP3 frames). */ void libfec_init(char *infile, char *outfile); void libfec_close(void); int libfec_read_adu(unsigned char *dst, unsigned int len); void libfec_write_adu(unsigned char *buf, unsigned int len); /* fec_len is the maximum packet size in the group */ fec_decode_t *libfec_new_group(unsigned char fec_k, unsigned char fec_n, unsigned long fec_len); void libfec_delete_group(fec_decode_t *group); fec_encode_t *libfec_new_encode(unsigned char fec_k, unsigned char fec_n); void libfec_delete_encode(fec_encode_t *encode); /****** Decoding routines ******/ /* * Add the packet with sequence number (0 <= pkt_seq < fec_n) to the * FEC group. */ void libfec_add_pkt(fec_decode_t *group, unsigned char pkt_seq, unsigned long len, unsigned char *data); /* * Decode the FEC group and extract the packet with seq idx. Note * that the original length information can not be recovered from the * encoded data. The resulting data can be padded with 0s. * * Return 1 on success, 0 on error */ unsigned int libfec_decode(fec_decode_t *group, unsigned char *dst, unsigned int idx, unsigned int len); /****** Encoding routines ******/ /* * Add an ADU (in sequence) into the encoding buffer. * * Return 0 on error, 1 on success. */ int libfec_add_adu(fec_encode_t *encode, unsigned long len, unsigned char *data); /* * after fec_k adus have been added, encode the packet with index IDX * into dst, with maximal length len. * * If idx < fec_k, then the original ADUs is copied. * * Returns 0 on error, length of the packet on success. */ unsigned int libfec_encode(fec_encode_t *encode, unsigned char *dst, unsigned int idx, unsigned int len); /* * Return the length of the biggest ADU in the group (and thus the * length of the FEC pkts with index >= fec_k. */ unsigned int libfec_max_length(fec_encode_t *encode); #endif /* LIBFEC_H__ */ poc-0.4.2/TODO0000664000175000001440000000636710214014115013431 0ustar manuelusers00000000000000X Dokumentation fuer aq.c X Dokumentation fuer dlist.[ch] X network.c schreiben X Support fuer RFC2250 in rtp.c fertig schreiben X Tabellen in mp3-read.c X poc.c fertig schreiben X pob.c erweitern X SSL in rtp.c X SSL in pob-2250.c poc-2250.c X SSL testen X subversion einrichten auf setf X conf.h bauen X unter linux, HP/UX kompilieren X Timing Problem bei SSL X errorlog2tex.pl schreiben X bv.[ch] Dokumentation schreiben X tex in subversion einchecken X FEC: X Galois X Matrixcode X FEC Code X poc-3119.c schreiben X pob-3119.c schreiben X Packetloss testen bei pob-3119 und pob-2250 X Packetloss randomisieren X Ueber Kommandozeile plossrate einstellen X Backpointer setzen bei einfuegen von leeren ADUs genauer angucken (RFC falsch!) X Documentation FEC X Documentation formatieren innerhalb der Funktionen X Algorithmus in transcoding.tex fertig schreiben X implementation.tex schreiben X Debug Code in pob-fec X pob-* mit statischen Ringbuffern schreiben, und nicht mit verketteten Listen X Buffering notes: X - ringbuffer for incoming packets X - use time of last played packet for reference X - handle strange cases X Vortrag fertig vorbereiten X Sleeptimeadjustment sinnvoller gestalten X poc-http.c wieder herstellen Xpob-fec fertigschreiben X - Dekodieren der Gruppen in fec-group.c X - Ausgabe der dekodierten Frames in der AQ X Sync probleme bei den Servern! X Studienarbeit fertigschreiben! X Memory Leaks entfernen Dokumentation fertig schreiben Nistnet testen ------------------------- X rtp.c Objektorientiert mit pack,unpack Pointer in der rtp_pkt_t Struktur X MallocBug angucken X Growing allocator for Vorbis packets - Content-Type bei HTTP servern X OGG Vorbis support X Einlesen von OGG Dateien X OGG pages einlesen X CRC implementieren X Schreiben von OGG pages X Vorbis stream einlesen X Vorbis Header einlesen X Vorbis Audiodaten einlesen X OGG HTTP Streamer X Vorbis Header an jeden neuen Client schicken X Schicken von OGG Pages (Syncen auf Granule Position) ---- 2te release X README schreiben X Manpages X id3tag support in mp3cue und mp3cut X print information in servers and clients not so intensive X check errors in mp3cue (?) X variable number of clients in poc-http X kbits anzeig in poc-* X Zeitanzeige in poc-* ---- 3te release BUG: - pob-fec: fec-group.c:113: fec_group_insert_pkt: Assertion `pkt->hdr.group_tstamp == group->tstamp' failed. - pob-fec: fec-rb.c:147: fec_rb_insert_pkt: Assertion `fec_rb[fec_rb_end].buf == ((void *)0)' failed. - counter wraparound checken - icecast/shoutcast gegenstelle fuer poc-http - id3tag support in poc-http (UDP socket?) - OGG RTP Streamer - Vorbis Pakete schreiben - Konvertierung nach OGG pages - Vorbis RTP Header support - 2tes Socket fuer Codebook - Einfuegen von Vorbis Daten in RTP Pakete - ipv6 testen - Vorbis multiple logical bitstreams - Pob-3119 pakete discarden, die zu spaet kommen - id3tags handeln - Protokolle um Metainformation erweitern (Anfrage) - Interleaving in poc-3119 und pob-3119 - aq mit Ringpuffer - select nach EINTR checken in pob - poc-http-inetd.c schreiben - dlist != NULL bei 1000.wav.mp3 mit rfc3119 - Kryptierte Keys einlesen - SSL bei poc-fec poc-0.4.2/mp3toadu.c0000664000175000001440000000214410204463252014637 0ustar manuelusers00000000000000#include "conf.h" #include #include #include #include #include #include "pack.h" #include "aq.h" #include "file.h" #include "mp3.h" static void usage(void) { printf("Usage: mp3toadu mp3file\n"); } int main(int argc, char *argv[]) { int retval = EXIT_SUCCESS; if (argc != 2) { usage(); return EXIT_FAILURE; } file_t infile; aq_t qin; aq_init(&qin); if (!file_open_read(&infile, argv[1])) { fprintf(stderr, "Could not open mp3 file: %s\n", argv[1]); retval = EXIT_FAILURE; goto exit; } mp3_frame_t frame; int ret; while (mp3_next_frame(&infile, &frame) > 0) { if (aq_add_frame(&qin, &frame)) { adu_t *adu = aq_get_adu(&qin); assert(adu != NULL); unsigned char len[2]; unsigned char *ptr = len; UINT16_PACK(ptr, adu->adu_size); ret = write(STDOUT_FILENO, len, 2); assert(ret == 2); ret = write(STDOUT_FILENO, adu->raw, adu->adu_size); assert(ret == adu->adu_size); free(adu); } } file_close(&infile); exit: aq_destroy(&qin); return retval; } poc-0.4.2/Makefile.lib0000664000175000001440000000174710206452756015165 0ustar manuelusers00000000000000# GNU Makefile for libraries # # Please compile with GNU make. # # 2005 bl0rg.net all: libs libfec-test libs: libfec.so CFLAGS += -Wall -O2 -fPIC -g # Create dependencies %.d: %.c $(CC) -MM $(CFLAGS) $< > $@ $(CC) -MM $(CFLAGS) $< | sed s/\\.o/.d/ >> $@ MP3_OBJS := mp3-read.o mp3-write.o mp3.o aq.o id3.o UTILS_OBJS := pack.o bv.o signal.o dlist.o file.o buf.o crc32.o FEC_OBJS := galois.o matrix.o fec.o fec-pkt.o fec-rb.o fec-group.o OBJS := $(MP3_OBJS) \ $(OGG_OBJS) \ $(NETWORK_OBJS) \ $(RTP_OBJS) \ $(UTILS_OBJS) \ $(FEC_OBJS) DEPS := $(patsubst %.o,%.d,$(OBJS)) include $(DEPS) # FEC library LIBFEC_OBJS := $(UTILS_OBJS) $(MP3_OBJS) $(FEC_OBJS) libfec.o include libfec.d libfec.a: $(LIBFEC_OBJS) ar r $@ $(LIBFEC_OBJS) ranlib $@ libfec.so: $(LIBFEC_OBJS) # $(LD) -o $@ -shared $(LIBFEC_OBJS) $(CC) -dynamiclib -o $@ $(LIBFEC_OBJS) include libfec-test.d libfec-test: libfec.a libfec-test.o $(CC) -o $@ libfec-test.o -L. -lfec poc-0.4.2/fec-pkt.h0000664000175000001440000000321410211673061014437 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef FEC_PKT_H__ #define FEC_PKT_H__ #include #include #define FEC_PKT_MAX_GROUP_SEQ 255 #define FEC_PKT_MAX_PACKET_SEQ 255 /*M \emph{Structure representing a FEC packet header.} **/ typedef struct fec_pkt_hdr_s { unsigned char magic; /* 8 bits magic: 0xfe */ unsigned char version; /* version, default 1 */ unsigned char group_seq; /* 8 bits group sequence number */ unsigned char packet_seq; /* 8 bits packet sequence number */ unsigned char fec_k; /* 8 bits FEC k parameter */ unsigned char fec_n; /* 8 bits FEC n parameter */ unsigned short fec_len; /* 16 bits FEC block length */ unsigned short len; /* 16 bits payload length */ unsigned long group_tstamp; /* 32 bits group timestamp in usecs */ } fec_pkt_hdr_t; /*M \emph{Maximal size of a FEC packet.} **/ #define FEC_PKT_SIZE 65535 /*M \emph{Header size of a FEC packet header.} **/ #define FEC_PKT_HDR_SIZE 14 /*M \emph{Maximal FEC packet payload size.} **/ #define FEC_PKT_PAYLOAD_SIZE (FEC_PKT_SIZE - FEC_PKT_HDR_SIZE) /*M \emph{FEC packet magic byte.} **/ #define FEC_PKT_MAGIC 0xfe /*M \emph{Structure representing a FEC packet.} **/ typedef struct fec_pkt_s { fec_pkt_hdr_t hdr; /* packet header */ unsigned char data[FEC_PKT_SIZE]; /* packet data: header + payload */ unsigned char *payload; /* pointer to payload into data */ } fec_pkt_t; /*M **/ void fec_pkt_init(/*@out@*/ fec_pkt_t *pkt); ssize_t fec_pkt_send(fec_pkt_t *pkt, int fd); ssize_t fec_pkt_sendto(fec_pkt_t *pkt, int fd, struct sockaddr *to, socklen_t tolen); ssize_t fec_pkt_read(fec_pkt_t *pkt, int fd); #endif /* FEC_PKT_H__ */ poc-0.4.2/poc-http.c0000664000175000001440000001633110214014115014633 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include #include #ifdef NEED_GETOPT_H__ #include #endif #include "file.h" #include "mp3.h" #include "network.h" #include "signal.h" #include "http.h" #include "misc.h" #ifdef WITH_IPV6 static int use_ipv6 = 0; #endif /* WITH_IPV6 */ static int finished = 0; #define MP3_BUF_LEN 65535 /* Maximal synchronization latency for sending packets in usecs. */ #define MAX_WAIT_TIME (1 * 1000 * 1000) #define MAX_FILENAME 256 static void sig_int(int signo) { finished = 1; } /*M \emph{Simple HTTP streaming server main loop.} The mainloop opens the MPEG Audio file \verb|filename|, reads each frame into an rtp packet and sends it out using HTTP. After sending a packet, the mainloop sleeps for the duration of the packet, synchronizing itself when the sleep is not accurate enough. If the sleep desynchronizes itself from the stream more than \verb|MAX_WAIT_TIME|, the synchronization is reset. **/ int poc_mainloop(http_server_t *server, char *filename, int quiet) { /*M Open file for reading. **/ file_t mp3_file; if (!file_open_read(&mp3_file, filename)) { fprintf(stderr, "Could not open mp3 file: %s\n", filename); return 0; } if (!quiet) fprintf(stderr, "\rStreaming %s...\n", filename); static long wait_time = 0; unsigned long frame_time = 0; mp3_frame_t frame; /*M Cycle through the frames and send them using HTTP. **/ while ((mp3_next_frame(&mp3_file, &frame) >= 0) && !finished) { /*M Get start time for this frame iteration. **/ struct timeval tv; gettimeofday(&tv, NULL); unsigned long start_sec, start_usec; start_sec = tv.tv_sec; start_usec = tv.tv_usec; /*M Go through HTTP main routine and check for timeouts, received data, etc... **/ if (!http_server_main(server, NULL)) { fprintf(stderr, "Http main error\n"); return 0; } /*M Write frame to HTTP clients. **/ int i; for (i = 0; i < server->num_clients; i++) { if ((server->clients[i].fd != -1) && (server->clients[i].found >= 2)) { int ret; ret = unix_write(server->clients[i].fd, frame.raw, frame.frame_size); if (ret != frame.frame_size) { fprintf(stderr, "Error writing to client %d: %d\n", i, ret); http_client_close(server, server->clients + i); } } } frame_time += frame.usec; wait_time += frame.usec; /*M Sleep for duration of frame. **/ if (wait_time > 1000) usleep(wait_time); /*M Print information. **/ if (!quiet) { static int count = 0; if ((count++) % 10 == 0) { if (mp3_file.size > 0) { fprintf(stderr, "\r%02ld:%02ld/%02ld:%02ld %7ld/%7ld (%3ld%%) %3ldkbit/s %4ldb ", (frame_time/1000000) / 60, (frame_time/1000000) % 60, (long)((float)(frame_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 60000, (long)((float)(frame_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 1000 % 60, mp3_file.offset, mp3_file.size, (long)(100*(float)mp3_file.offset/(float)mp3_file.size), frame.bitrate, frame.frame_size); } else { fprintf(stderr, "\r%02ld:%02ld %ld %3ldkbit/s %4ldb ", (frame_time/1000000) / 60, (frame_time/1000000) % 60, mp3_file.offset, frame.bitrate, frame.frame_size); } } fflush(stderr); } /*M Get length of iteration. **/ gettimeofday(&tv, NULL); unsigned long len = (tv.tv_sec - start_sec) * 1000000 + (tv.tv_usec - start_usec); wait_time -= len; if (abs(wait_time) > MAX_WAIT_TIME) wait_time = 0; } if (!file_close(&mp3_file)) { fprintf(stderr, "Could not close mp3 file %s\n", filename); return 0; } return 1; } /*M \emph{Print usage information.} **/ static void usage(void) { fprintf(stderr, "Usage: ./poc-http [-s address] [-p port] [-q] [-c clients]"); #ifdef WITH_IPV6 fprintf(stderr, " [-6]"); #endif fprintf(stderr, " files...\n"); fprintf(stderr, "\t-s address : source address (default 0.0.0.0)\n"); fprintf(stderr, "\t-p port : port to listen on (default 8000)\n"); fprintf(stderr, "\t-q : quiet\n"); fprintf(stderr, "\t-c clients : maximal number of clients (default 0, unlimited)\n"); #ifdef WITH_IPV6 fprintf(stderr, "\t-6 : use ipv6\n"); #endif } /*M \emph{HTTP server main routine.} **/ int main(int argc, char *argv[]) { int retval = 0; char *address = NULL; unsigned short port = 8000; int quiet = 0; int max_clients = 0; http_server_t server; http_server_reset(&server); if (argc <= 1) { usage(); return 1; } int c; while ((c = getopt(argc, argv, "hs:p:qc:" #ifdef WITH_IPV6 "6" #endif /* WITH_IPV6 */ )) >= 0) { switch (c) { #ifdef WITH_IPV6 case '6': use_ipv6 = 1; break; #endif /* WITH_IPV6 */ case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = (unsigned short)atoi(optarg); break; case 'c': max_clients = (unsigned short)atoi(optarg); break; case 'q': quiet = 1; break; case 'h': default: usage(); retval = EXIT_FAILURE; goto exit; } } if (optind == argc) { usage(); retval = EXIT_FAILURE; goto exit; } if (address == NULL) { #ifdef WITH_IPV6 if (use_ipv6) address = strdup("0::0"); else address = strdup("0"); #else address = strdup("0"); #endif /* WITH_IPV6 */ } /*M Open the listening socket. **/ int sock = -1; #ifdef WITH_IPV6 if (use_ipv6) sock = net_tcp6_listen_socket(address, port); else sock = net_tcp4_listen_socket(address, port); #else sock = net_tcp4_listen_socket(address, port); #endif /* WITH_IPV6 */ if (sock < 0) { perror("Could not create socket"); retval = EXIT_FAILURE; goto exit; } if (!http_server_init(&server, HTTP_MIN_CLIENTS, max_clients, NULL, sock)) { fprintf(stderr, "Could not initialise HTTP server\n"); retval = EXIT_FAILURE; goto exit; } if (sig_set_handler(SIGINT, sig_int) == SIG_ERR) { retval = EXIT_FAILURE; goto exit; } /*M Read in mp3 files one after the other. **/ int i; for (i=optind; (i. BUILD ===== You need a C99 compliant compiler to compile poc. Check conf.h if needed. It works under Linux, FreeBSD, MacOSX. TODO ==== Write a real Makefile and check portability. Test the programs thoroughly. Write input plugins for common audio players (itunes, xmms, winamp). Implement feedback into the FEC protocol to allow for autoadaptive FEC. Scale the mp3 to reduce FEC overhead. poc-0.4.2/matrix.c0000664000175000001440000002173310210123147014405 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "matrix.h" #include #include /*M \emph{Print a $m \times n$ matrix.} **/ void matrix_print(gf *a, int m, int n) { int row; for (row = 0; row < m; row++) { int col; for (col = 0; col < n; col++) fprintf(stderr, "%-3u ", a[row * n + col]); fprintf(stderr, "\n"); } } /*M \emph{Matrix multiplication.} Computes $c = a * b$, with $a \in \gf{2^8}^{n \times k}, b \in \gf{2^8}^{k \times m}, c \in \gf{2^8}^{n \times m}$. **/ void matrix_mul(gf *a, gf *b, gf *c, int n, int k, int m) { int row; for (row = 0; row < n; row++) { int col; for (col = 0; col < m; col++) { gf *pa = a + row * k; gf *pb = b + col; gf acc = 0; int i; for (i = 0; i < k; i++, pa++, pb += m) acc = GF_ADD(acc, GF_MUL(*pa, *pb)); c[row * m + col] = acc; } } } /*M \emph{Computes the inverse of a matrix.} Computes the inverse of \verb|a| into \verb|a| using Gauss-Jordan elimination. Transform the matrix using pivoting and Gauss elimination to bring it into the form of the identity matrix, and apply the transformations to the identity matrix. Returns 0 on error, 1 on success **/ int matrix_inv(gf *a, int k) { /*M Bookkeeping on the pivoting. **/ int indxc[k]; int indxr[k]; /*M \verb|id_row| is used to compare the pivot row to the corresponding identity row in order to speed up computation. **/ gf id_row[k]; /*M \verb|ipiv| marks elements already used as pivots. **/ int ipiv[k]; /*M Initialize \verb|id_row| and \verb|ipiv|. **/ int i; for (i = 0; i < k; i++) { id_row[i] = 0; ipiv[i] = 0; } int col; for (col = 0; col < k; col++) { /*M Look for a non-zero element to use as pivot. **/ int irow = -1, icol = -1; /*M First check the diagonal. **/ if ((ipiv[col] != 1) && (a[col * k + col] != 0)) { irow = col; icol = col; } else { /*M Then search the matrix. **/ int row; for (row = 0; row < k; row++) { if (ipiv[row] != 1) { for (i = 0; i < k; i++) { if (ipiv[i] == 0) { if (a[row * k + i] != 0) { irow = row; icol = i; goto found_pivot; } } else if (ipiv[i] > 1) { fprintf(stderr, "Singular matrix\n"); return 0; } } } } fprintf(stderr, "Pivot not found\n"); return 0; } found_pivot: /*M Now we got a pivot element in \verb|icol| and \verb|irow|. **/ ++(ipiv[icol]); /*M Swap rows so the pivot is on the diagonal. **/ if (irow != icol) { gf tmp; for (i = 0; i < k; i++) { tmp = a[irow * k + i]; a[irow * k + i] = a[icol * k + i]; a[icol * k + i] = tmp; } } /*M Remember the pivot position. **/ indxr[col] = irow; indxc[col] = icol; gf *pivot_row = a + icol * k; /*M Divide pivot row with the pivot element. **/ gf c = pivot_row[icol]; if (c == 0) { fprintf(stderr, "Singular matrix\n"); return 0; } else if (c != 1) { c = GF_INV(c); pivot_row[icol] = 1; for (i = 0; i < k; i++) pivot_row[i] = GF_MUL(c, pivot_row[i]); } /*M Reduce rows. If the pivot row is the identity row, we don't need to substract the pivot row **/ id_row[icol] = 1; if (bcmp(pivot_row, id_row, k * sizeof(gf)) != 0) { gf *p; for (p = a, i = 0; i < k; i++, p += k) { /*M Don't reduce the pivot row. **/ if (i != icol) { gf c = p[icol]; /*M Zero out the element corresponding to the pivot element and substract the pivot row multiplied by the zeroed out element. **/ p[icol] = 0; gf_add_mul(p, pivot_row, c, k); } } } id_row[icol] = 0; } /*M Descramble the solution. **/ for (col = k - 1; col >= 0; col--) { if (indxr[col] != indxc[col]) { int row; gf tmp; for (row = 0; row < k; row++) { tmp = a[row * k + indxr[col]]; a[row * k + indxr[col]] = a[row * k + indxc[col]]; a[row * k + indxc[col]] = tmp; } } } return 1; } /*M \emph{Computes the inverse of a Vandermonde matrix.} \begin{definition} A \emph{Vandermonde matrix} of size $N \times N$ is completely determined by $N$ arbitrary numbers $x_1, x_2, \dots, x_N$, in terms of which its $N^2$ components are the integer powers $x_i^{j-1}, i, j = 1, \dots, N$. \end{definition} % Write full matrix out We use the $i$'s as rows, the $j$'s as columns. The linear system $A \cdot c = y$ solves for the coefficients $c$ which fit a polynomial to $(x_j, y_j), j = 1, \dots, N$. Let $P_j(x)$ be the Lagrange polynomial of degree $N-1$ defined by $x_1, \dots, x_N$. We know that \[P_j(x_i) = \delta_{ij} = \sum_{k=1}^NA_{jk}x_i^{k-1}\], therefore the solution of $A \cdot c = y$ is just $c_j = \sum_{k=1}^NA_{kj}y_k$. In our routine we are only interested by $A_{kj}$, the inverse of the Vandermonde matrix. Vandermonde systems are ill-conditioned, but this doesn't affect us, as we work in a finite field. First, we calculate $P(x) = \prod_{i=1}^k (x - x_i)$, which is then synthetically divided by $x_j$, to obtain $\prod_{i=1\\ i\neq j}^n (x - x_i)$, and then divided by $\prod_{i=1\\ i \neq j}^n (x_j - x_i)$ to obtain $P_j(x)$, which is the $j$-th row of the inverted matrix. Only uses the second row of the matrix \verb|a|, containing the $x_i$ coefficients. Returns $1$ on success, $0$ on error. **/ int matrix_inv_vandermonde(gf *a, int k) { /*M Check for a degenerate case. **/ if (k == 1) return 0; /*M \verb|p| holds the matrix coefficients \verb|x_i|. **/ gf p[k]; /*M \verb|c| holds the coefficient of $P(x) = \prod_{i=0}^{k-1} (x - p_i)$ **/ gf c[k]; int i, j; for (i = 0, j = 1; i < k; i++, j += k) { c[i] = 0; p[i] = a[j]; } /*M Construct coefficients. We know \verb|c[k] = 1| implicitly. Start with $P_0 = x - x_0$. We are in $2^m$, so $x_0 = - x_0$. **/ c[k-1] = p[0]; for (i = 1; i < k; i++) { gf p_i = p[i]; /*M At each step $P_i = x \cdot P_{i - 1} - p_i \cdot P_{i - 1}$, so \verb|c[j] = c[j] + p[i] * c[j+1]|, \verb|c[k] = 1| (implicit), and \verb|c[k-1] = c[k-1] + p_i|. **/ for (j = k - 1 - i; j < k - 1; j++) c[j] = GF_ADD(c[j], GF_MUL(p_i, c[j+1])); c[k-1] = GF_ADD(c[k-1], p_i); } /*M \verb|b| holds the coefficient for the matrix inversion. **/ gf b[k]; /*M Do the synthetic division. **/ int row; for (row = 0; row < k; row++) { gf x = p[row]; gf t = 1; b[k-1] = 1; /* c[k] */ for (i = k - 2; i >= 0; i--) { b[i] = GF_ADD(c[i+1], GF_MUL(x, b[i+1])); t = GF_ADD(GF_MUL(x, t), b[i]); } int col; for (col = 0; col < k; col++) a[col * k + row] = GF_MUL(GF_INV(t), b[col]); } return 1; } /*C **/ #ifdef MATRIX_TEST void testit(char *name, unsigned int result, unsigned int should) { if (result == should) { printf("Test %s was successful\n", name); } else { printf("Test %s was not successful, %u should have been %u\n", name, result, should); } } int main(void) { gf matrix1[4*4] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; gf matrix2[4*4]; gf matrix3[4*4] = { 1, 5, 3, 18, 5, 6, 19, 21, 9, 0, 0, 7, 4, 5, 4, 83 }; /* from mathematica */ gf matrix4[4*4] = { 148, 39, 173, 174, 55, 134, 87, 159, 170, 142, 46, 94, 161, 105, 80, 239 }; gf matrix5[4*4] = {1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}; gf_init(); gf vand1[4*4] = { 1, 2, GF_MUL(2, 2), GF_MUL(2, GF_MUL(2, 2)), 1, 3, GF_MUL(3, 3), GF_MUL(3, GF_MUL(3, 3)), 1, 5, GF_MUL(5, 5), GF_MUL(5, GF_MUL(5, 5)), 1, 7, GF_MUL(7, 7), GF_MUL(7, GF_MUL(7, 7)) }; gf vand2[4*4]; testit("invert singular matrix", matrix_inv(matrix5, 4), 0); memcpy(matrix2, matrix1, sizeof(matrix1)); testit("invert matrix", matrix_inv(matrix2, 4), 1); int i; for (i = 0; i < 16; i++) testit("invert matrix", matrix2[i], matrix1[i]); testit("invert matrix", matrix_inv(matrix3, 4), 1); for (i = 0; i < 16; i++) testit("invert matrix", matrix3[i], matrix4[i]); memcpy(vand2, vand1, sizeof(vand1)); testit("vandermonde invert matrix", matrix_inv_vandermonde(vand1, 4), 1); testit("invert matrix", matrix_inv(vand2, 4), 1); for (i = 0; i < 16; i++) testit("vandermonde invert matrix", vand1[i], vand2[i]); return 0; } #endif /* MATRIX_TEST */ poc-0.4.2/bv.c0000664000175000001440000002347410210123147013514 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include "bv.h" /*S Bit vector implementation **/ /*M \emph{Sanity check.} Assume bytes are at least 8 bits long and longs are at least 32 bits long **/ #if (CHAR_BIT < 8) #error "char should be at least 8 bits long" #endif /*M \emph{Get lower bits of byte.} Get the b lower bits of byte x. **/ #define LOWERBITS(x, b) ((b) ? (x) & ((2 << ((b) - 1)) - 1) : 0) /*M \emph{Get higher bits of byte.} Get the b higher bits of byte x. **/ #define HIGHERBITS(x, b) (((x) & 0xff) >> (8 - (b))) /*M \emph{Initialize a bit vector structure.} Initialize a bit vector structure bv with byte data data, and bit length len. The internal index of the bit vector is set to 0, so that future \verb|bv_get_bits| or \verb|bv_put_bits| will access the first bit. **/ void bv_init(bv_t *bv, unsigned char *data, unsigned int len) { assert(bv != NULL); assert(data != NULL); bv->data = data; bv->len = len; bv->idx = 0; } /*M \emph{Reset bit vector.} Reset the internal index of the bit vector to 0, so that future \verb|bv_get_bits| or \verb|bv_put_bits| will access the first bit. **/ void bv_reset(bv_t *bv) { assert(bv != NULL); bv->idx = 0; } /*M \emph{Get next bits of bit vector.} Returns the next numbits bits from bv. **/ unsigned long bv_get_bits(bv_t *bv, unsigned int numbits) { assert(bv != NULL); assert(bv->data != NULL); assert((numbits <= 32) || "Can not read more than 32 bits from a bit vector"); assert(bv->len > bv->idx); assert(((bv->len - bv->idx) > numbits) || "Bit buffer of bit vector is too small"); unsigned int cidx = bv->idx >> 3; /* char index */ /*M Bit overflow from previous char. **/ unsigned int overflow = bv->idx & 0x7; bv->idx += numbits; /*M Most significant bit first. **/ if (numbits <= (8 - overflow)) return HIGHERBITS(bv->data[cidx] << overflow, numbits); /*M Length in bytes of bitstring. **/ unsigned int len = ((numbits + overflow) >> 3) + 1; /*M Number of bits of bitstring in first byte. **/ unsigned long res = LOWERBITS(bv->data[cidx++], 8 - overflow); unsigned int i; for (i = 1; i < len - 1; i++) res = (res << 8) | (bv->data[cidx++] & 0xFF); /*M Number of bits in last byte. **/ unsigned int lastbits = (overflow + numbits) & 0x07; res = (res << lastbits) | HIGHERBITS(bv->data[cidx], lastbits); return res; } /*M \emph{Put bits into bit vector.} Put the first numbits bits of bits into the bit vector bv. Returns 1 on success, 0 on error. **/ int bv_put_bits(bv_t *bv, unsigned long bits, unsigned int numbits) { assert(bv != NULL); assert(bv->data != NULL); assert(bv->len > bv->idx); assert((numbits <= 32) || "Can not write more than 32 bits into a bit vector"); if (numbits > (bv->len - bv->idx)) return 0; unsigned int cidx = bv->idx >> 3; unsigned int overflow = bv->idx & 0x07; bv->idx += numbits; /*M Put first bit as highest order bit of 32 bit long. **/ bits <<= (32 - numbits); if ((overflow + numbits) < 8) { bv->data[cidx] = (HIGHERBITS(bv->data[cidx], overflow) << (8 - overflow)) | (HIGHERBITS(bits >> 24, numbits) << (8 - overflow - numbits)) | LOWERBITS(bv->data[cidx], 8 - overflow - numbits); return 1; } else { bv->data[cidx] = (HIGHERBITS(bv->data[cidx], overflow) << (8 - overflow)) | HIGHERBITS(bits >> 24, 8 - overflow); } cidx++; bits <<= 8 - overflow; unsigned int len = ((numbits + overflow) >> 3) + 1; unsigned int i; for (i = 1; i < len - 1; i++, bits <<= 8) bv->data[cidx++] = (bits >> 24) & 0xff; unsigned int lastbits = (overflow + numbits) & 0x07; bv->data[cidx] = (HIGHERBITS((bits >> 24) & 0xff, lastbits) << (8 - lastbits)) | LOWERBITS(bv->data[cidx], 8 - lastbits); return 1; } /*C **/ #ifdef BV_TEST #include void testit(char *name, int result, int should) { if (result == should) { printf("Test %s was successful\n", name); } else { printf("Test %s was not successful, %x should have been %x\n", name, result, should); } } int main(void) { unsigned char test[4] = {0xaa, 0xaa, 0xaa, 0xaa}, test2[4] = {0}; bv_t bv; /* test LOWERBITS */ testit("LOWERBITS 1 bit", LOWERBITS(0x1, 1), 0x1); testit("LOWERBITS 2 bits", LOWERBITS(0x2, 2), 0x2); testit("LOWERBITS 2 bits", LOWERBITS(0x2, 1), 0x0); testit("LOWERBITS 8 bits", LOWERBITS(0xf, 8), 0xf); /* test HIGHERBITS */ testit("HIGHERBITS 1 bit", HIGHERBITS(0xff, 1), 0x1); testit("HIGHERBITS 2 bits", HIGHERBITS(0xff, 2), 0x3); testit("HIGHERBITS 2 bits", HIGHERBITS(0x7f, 2), 0x1); testit("HIGHERBITS 8 bits", HIGHERBITS(0xff, 8), 0xff); bv_init(&bv, test, 32); /* test bv_get_bits without char border crossing */ testit("bv_get_bits noborder 1 bit", bv_get_bits(&bv, 1), 1); testit("bv_get_bits noborder 1 bit", bv_get_bits(&bv, 1), 0); testit("bv_get_bits noborder 2 bits", bv_get_bits(&bv, 2), 2); testit("bv_get_bits noborder 3 bits", bv_get_bits(&bv, 3), 5); /* test bv_get_bits accross border */ testit("bv_get_bits border 2 bits", bv_get_bits(&bv, 2), 1); testit("bv_get_bits border 8 bits", bv_get_bits(&bv, 8), 0x55); testit("bv_get_bits border 12 bits", bv_get_bits(&bv, 12), 0x555); bv_reset(&bv); /* test bv_get_bits on 32 bits */ testit("bv_get_bits border 32 bits", bv_get_bits(&bv, 32), 0xaaaaaaaa); bv_init(&bv, test2, 32); /* test bv_put_bits without char border crossing */ testit("bv_put_bits noborder 4 bits", bv_put_bits(&bv, 0x5, 4), 1); bv_reset(&bv); testit("bv_put_bits noborder 4 bits get 4 bits", bv_get_bits(&bv, 4), 0x5); bv_reset(&bv); testit("bv_put_bits noborder 4 bits get 1 bit", bv_get_bits(&bv, 1), 0); testit("bv_put_bits noborder 4 bits get 1 bit", bv_get_bits(&bv, 1), 1); testit("bv_put_bits noborder 4 bits get 2 bits", bv_get_bits(&bv, 2), 1); bv_reset(&bv); testit("bv_put_bits noborder 8 bits", bv_put_bits(&bv, 0x5a, 8), 1); bv_reset(&bv); testit("bv_put_bits noborder 8 bits get 4 bits", bv_get_bits(&bv, 4), 0x5); testit("bv_put_bits noborder 8 bits get 1 bit", bv_get_bits(&bv, 1), 1); testit("bv_put_bits noborder 8 bits get 1 bit", bv_get_bits(&bv, 1), 0); testit("bv_put_bits noborder 8 bits get 2 bits", bv_get_bits(&bv, 2), 2); bv_reset(&bv); testit("bv_put_bits noborder 16 bits", bv_put_bits(&bv, 0x5a5a, 16), 1); bv_reset(&bv); testit("bv_put_bits noborder 16 bits get 4 bits", bv_get_bits(&bv, 4), 0x5); testit("bv_put_bits noborder 16 bits get 1 bit", bv_get_bits(&bv, 1), 1); testit("bv_put_bits noborder 16 bits get 1 bit", bv_get_bits(&bv, 1), 0); testit("bv_put_bits noborder 16 bits get 2 bits", bv_get_bits(&bv, 2), 2); testit("bv_put_bits noborder 16 bits get 4 bits", bv_get_bits(&bv, 4), 0x5); testit("bv_put_bits noborder 16 bits get 1 bit", bv_get_bits(&bv, 1), 1); testit("bv_put_bits noborder 16 bits get 1 bit", bv_get_bits(&bv, 1), 0); testit("bv_put_bits noborder 16 bits get 2 bits", bv_get_bits(&bv, 2), 2); bv_reset(&bv); testit("bv_put_bits border 8 bits", bv_put_bits(&bv, 0x55, 7), 1); testit("bv_put_bits border 8 bits", bv_put_bits(&bv, 0x0, 1), 1); bv_reset(&bv); testit("bv_put_bits border 8 bits get 4 bits", bv_get_bits(&bv, 4), 0xa); testit("bv_put_bits border 8 bits get 1 bit", bv_get_bits(&bv, 1), 1); testit("bv_put_bits border 8 bits get 1 bit", bv_get_bits(&bv, 1), 0); testit("bv_put_bits border 8 bits get 2 bits", bv_get_bits(&bv, 2), 2); bv_reset(&bv); testit("bv_put_bits border 16 bits", bv_put_bits(&bv, 0x55, 7), 1); testit("bv_put_bits border 16 bits", bv_put_bits(&bv, 0x2, 3), 1); testit("bv_put_bits border 16 bits", bv_put_bits(&bv, 0x2a, 6), 1); bv_reset(&bv); testit("bv_put_bits border 16 bits get 4 bits", bv_get_bits(&bv, 4), 0xa); testit("bv_put_bits border 16 bits get 1 bit", bv_get_bits(&bv, 1), 1); testit("bv_put_bits border 16 bits get 1 bit", bv_get_bits(&bv, 1), 0); testit("bv_put_bits border 16 bits get 2 bits", bv_get_bits(&bv, 2), 2); testit("bv_put_bits border 16 bits get 4 bits", bv_get_bits(&bv, 4), 0xa); testit("bv_put_bits border 16 bits get 1 bit", bv_get_bits(&bv, 1), 1); testit("bv_put_bits border 16 bits get 1 bit", bv_get_bits(&bv, 1), 0); testit("bv_put_bits border 16 bits get 2 bits", bv_get_bits(&bv, 2), 2); bv_reset(&bv); testit("bv_put_bits border 32 bits", bv_put_bits(&bv, 1, 4), 1); testit("bv_put_bits border 32 bits", bv_put_bits(&bv, 2, 4), 1); testit("bv_put_bits border 32 bits", bv_put_bits(&bv, 3, 4), 1); testit("bv_put_bits border 32 bits", bv_put_bits(&bv, 4, 4), 1); testit("bv_put_bits border 32 bits", bv_put_bits(&bv, 5, 4), 1); testit("bv_put_bits border 32 bits", bv_put_bits(&bv, 6, 4), 1); testit("bv_put_bits border 32 bits", bv_put_bits(&bv, 7, 4), 1); testit("bv_put_bits border 32 bits", bv_put_bits(&bv, 8, 4), 1); bv_reset(&bv); testit("bv_put_bits border 32 bits", bv_get_bits(&bv, 32), 0x12345678); bv_reset(&bv); bv_put_bits(&bv, 0xffff, 16); bv_reset(&bv); bv_put_bits(&bv, 0x0, 2); bv_put_bits(&bv, 0x3, 2); bv_put_bits(&bv, 0x0, 3); bv_reset(&bv); testit("bv_put_bits rest 8 bits", bv_get_bits(&bv, 16), 0x31FF); bv_reset(&bv); bv_put_bits(&bv, 0xffff, 16); bv_reset(&bv); bv_put_bits(&bv, 0x0, 9); bv_reset(&bv); testit("bv_put_bits rest 8 bits", bv_get_bits(&bv, 16), 0x7F); bv_reset(&bv); bv_put_bits(&bv, 0xffff, 16); bv_reset(&bv); bv_put_bits(&bv, 0x0, 2); bv_put_bits(&bv, 0x0, 2); bv_put_bits(&bv, 0x0, 3); bv_put_bits(&bv, 0x0, 2); bv_reset(&bv); testit("bv_put_bits rest 8 bits", bv_get_bits(&bv, 16), 0x7F); bv_reset(&bv); bv_put_bits(&bv, 0xffff, 16); bv_reset(&bv); bv_get_bits(&bv, 4); bv_put_bits(&bv, 0x0, 2); bv_reset(&bv); testit("bv_put_bits rest 8 bits", bv_get_bits(&bv, 16), 0xF3FF); return 0; } #endif poc-0.4.2/matrix.h0000664000175000001440000000056110210123147014406 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net Based on an implementation by Luigi Rizzo and Numerical Recipes in C **/ #ifndef MATRIX_H__ #define MATRIX_H__ #include "galois.h" void matrix_mul(gf *a, gf *b, gf *c, int n, int k, int m); int matrix_inv(gf *a, int k); int matrix_inv_vandermonde(gf *a, int k); void matrix_print(gf *a, int m, int n); /*C **/ #endif /* MATRIX_H__ */ poc-0.4.2/poc-3119.c0000664000175000001440000002425410214014115014254 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #ifdef WITH_OPENSSL #include #include #include #endif #include #include #include #include #include #include #include #ifdef NEED_GETOPT_H__ #include #endif #include "mp3.h" #include "aq.h" #include "network.h" #include "rtp.h" #include "signal.h" #include "file.h" #ifdef WITH_IPV6 static int use_ipv6 = 0; #endif /* WITH_IPV6 */ #define MAX_FILENAME 256 #ifdef WITH_OPENSSL RSA *rsa = NULL; #endif #ifdef DEBUG_PLOSS int ploss_rate = 20; #endif /* DEBUG_PLOSS */ static int finished = 0; /*M \emph{Maximal synchronization latency for sending packets.} In usecs. **/ #define MAX_WAIT_TIME (1 * 1000 * 1000) rtp_pkt_t pkt; static void sig_int(int signo) { finished = 1; } unsigned long cksum(char *data, int len) { unsigned long res = 0; int i; for (i = 0; i < len; i++) res += data[i]; return res; } /*M \emph{Simple RTP RFC3119 streaming server main loop.} The mainloop opens the MPEG Audio file \verb|filename|, reads each frame into an ADU queue, converts it into a MPEG adu (if possible), fills an RTP packet with this new ADU, and sends it out using the UDP socket \verb|sock|. After sending a packet, the mainloop sleeps for the duration of the packet, synchronizing itself when the sleep is not accurate enough. If the sleep desynchronizes itself from the stream more than \verb|MAX_WAIT_TIME|, the synchronization is reset. **/ int poc_mainloop(int sock, char *filename, int quiet) { /*M Open MPEG file for reading. **/ file_t mp3_file; if (!file_open_read(&mp3_file, filename)) { fprintf(stderr, "Could not open mp3 file: %s\n", filename); return 0; } /*M Initialize the ADU queue used to convert MPEG frames into MPEG adus. **/ aq_t adu_queue; aq_init(&adu_queue); static long wait_time = 0; unsigned long rtp_time = 0; /*M Get start time. **/ struct timeval tv; gettimeofday(&tv, NULL); unsigned long start_sec, start_usec; start_sec = tv.tv_sec; start_usec = tv.tv_usec; /*M Cycle through the frames, convert them to ADUs and send them using RTP. **/ mp3_frame_t mp3_frame; while ((mp3_next_frame(&mp3_file, &mp3_frame) > 0) && !finished) { /*M Add the MPEG frame to the adu queue. **/ if (aq_add_frame(&adu_queue, &mp3_frame)) { /*M An ADU could be generated. **/ adu_t *adu = aq_get_adu(&adu_queue); assert(adu != NULL); /*M Fill rtp packet with the newly generated ADU. **/ pkt.timestamp = (rtp_time) / 11.1111; unsigned char *ptr = pkt.data + pkt.hlen; /* need an extended header? */ pkt.length = mp3_frame_size(adu); if (pkt.length > ((1 << 6) - 1)) ptr++; memcpy(ptr, adu->raw, pkt.length); /*M Sign the packet if Openssl is activated. **/ #ifdef WITH_OPENSSL if (rsa != NULL) { if (!rtp_pkt_sign(&pkt, rsa)) { fprintf(stderr, "\nCould not sign packet\n"); free(adu); aq_destroy(&adu_queue); return 0; } pkt.b.pt = RTP_PT_SMPA; } #endif /*M Simulate packet loss. **/ #ifdef DEBUG_PLOSS if ((random() % 100) >= ploss_rate ) { #endif /* DEBUG_PLOSS */ /* send rtp packet */ if (rtp_pkt_send(&pkt, sock) < 0) { if (errno == ENOBUFS) { fprintf(stderr, "Output buffers full, waiting...\n"); } else { perror("Error while sending packet"); free(adu); aq_destroy(&adu_queue); return 0; } } #ifdef DEBUG_PLOSS } #endif /* DEBUG_PLOSS */ /*M Update the MPEG timestamp. **/ rtp_time += adu->usec; /*M Update the time we have to wait. **/ wait_time += adu->usec; /*M Sender synchronisation (\verb|sleep| until the next ADU has to be sent. **/ if (wait_time > 1000) usleep(wait_time); /*M Print sender information. **/ if (!quiet) { static int count = 0; if ((count++ % 10) == 0) { if (mp3_file.size > 0) { fprintf(stdout, "\r%02ld:%02ld/%02ld:%02ld %7ld/%7ld (%3ld%%) %3ldkbit/s %4ldb ", (rtp_time/1000000) / 60, (rtp_time/1000000) % 60, (long)((float)(rtp_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 60000, (long)((float)(rtp_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 1000 % 60, mp3_file.offset, mp3_file.size, (long)(100*(float)mp3_file.offset/(float)mp3_file.size), adu->bitrate, adu->adu_size); } else { fprintf(stdout, "\r%02ld:%02ld %ld %3ldkbit/s %4ldb ", (rtp_time/1000000) / 60, (rtp_time/1000000) % 60, mp3_file.offset, adu->bitrate, adu->adu_size); } } fflush(stdout); } free(adu); } /*M Get length of iteration. **/ gettimeofday(&tv, NULL); unsigned long len = (tv.tv_sec - start_sec) * 1000000 + (tv.tv_usec - start_usec); wait_time -= len; if (abs(wait_time) > MAX_WAIT_TIME) wait_time = 0; start_sec = tv.tv_sec; start_usec = tv.tv_usec; } /*M Destroy the ADU queue and close the MPEG file. **/ aq_destroy(&adu_queue); if (!file_close(&mp3_file)) { fprintf(stderr, "Could not close mp3 file\n"); return 0; } return 1; } /*M \emph{Print usage information.} **/ static void usage(void) { fprintf(stderr, "Usage: ./poc [-s address] [-p port] [-q] [-t ttl]"); #ifdef WITH_OPENSSL fprintf(stderr, " [-c pem]"); #endif /* WITH_OPENSSL */ #ifdef WITH_IPV6 fprintf(stderr, " [-6]"); #endif /* WITH_IPV6 */ fprintf(stderr, "files...\n"); fprintf(stderr, "\t-s address : destination address (default 224.0.1.23 or ff02::4)\n"); fprintf(stderr, "\t-p port : destination port (default 1500)\n"); fprintf(stderr, "\t-q : quiet\n"); fprintf(stderr, "\t-t ttl : multicast ttl (default 1)\n"); #ifdef WITH_OPENSSL fprintf(stderr, "\t-c pem : sign with private RSA key\n"); #endif /* WITH_OPENSSL */ #ifdef DEBUG_PLOSS fprintf(stderr, "\t-P ploss : packet loss interval\n"); #endif /* DEBUG_PLOSS */ #ifdef WITH_IPV6 fprintf(stderr, "\t-6 : use ipv6\n"); #endif /* WITH_IPV6 */ } /*M \emph{Main server routine.} Calls the mainloop for each filename given on the command line. **/ int main(int argc, char *argv[]) { int retval = 0; char *address = NULL; unsigned short port = 1500; unsigned int ttl = 1; int quiet = 0; /*M Process the command line arguments. **/ int c; while ((c = getopt(argc, argv, "hs:p:t:qc:P:" #ifdef WITH_OPENSSL "c:" #endif /* WITH_OPENSSL */ #ifdef WITH_IPV6 "6" #endif /* WITH_IPV6 */ )) >= 0) { switch (c) { #ifdef WITH_IPV6 case '6': use_ipv6 = 1; break; #endif /* WITH_IPV6 */ case 's': if (address != NULL) free(address); address = strdup(optarg); break; case 'p': port = (unsigned short)atoi(optarg); break; case 'q': quiet = 1; break; case 't': ttl = (unsigned int)atoi(optarg); break; /*M If Openssl is used, read in the RSA key. **/ #ifdef WITH_OPENSSL case 'c': { if (rsa != NULL) { RSA_free(rsa); rsa = NULL; } FILE *f = NULL; if (!(f = fopen(optarg, "r"))) { fprintf(stderr, "Could not open private key %s\n", optarg); retval = EXIT_FAILURE; goto exit; } if (!(rsa = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL))) { fprintf(stderr, "Could not read private key %s\n", optarg); fclose(f); retval = EXIT_FAILURE; goto exit; } fclose(f); OpenSSL_add_all_digests(); break; } #endif /* WITH_OPENSSL */ #ifdef DEBUG_PLOSS case 'P': { static struct timeval tv; gettimeofday(&tv, NULL); srandom(tv.tv_sec); ploss_rate = atoi(optarg); break; } #endif /* DEBUG_PLOSS */ case 'h': default: usage(); retval = EXIT_FAILURE; goto exit; } } if (optind == argc) { usage(); retval = EXIT_FAILURE; goto exit; } if (address == NULL) { #ifdef WITH_IPV6 if (use_ipv6) address = strdup("ff02::4"); else address = strdup("224.0.1.23"); #else address = strdup("224.0.1.23"); #endif /* WITH_IPV6 */ } if (sig_set_handler(SIGINT, sig_int) == SIG_ERR) { retval = EXIT_FAILURE; goto exit; } /*M Open the sending socket. **/ int sock; #ifdef WITH_IPV6 if (use_ipv6) sock = net_udp6_send_socket(address, port, ttl); else sock = net_udp4_send_socket(address, port, ttl); #else sock = net_udp4_send_socket(address, port, ttl); #endif /* WITH_IPV6 */ if (sock < 0) { fprintf(stderr, "Could not open socket\n"); retval = EXIT_FAILURE; goto exit; } /*M Initialize the RTP packet (fill common header fields). **/ rtp_rfc3119_pkt_init(&pkt); pkt.b.pt = RTP_DYN; pkt.b.m = 0; /*M Go through all files given on command line and stream them. **/ int i; for (i = optind; (i < argc) && !finished; i++) { assert(argv[i] != NULL); unsigned char filename[MAX_FILENAME]; strncpy(filename, argv[i], MAX_FILENAME - 1); filename[MAX_FILENAME - 1] = '\0'; if (!poc_mainloop(sock, filename, quiet)) continue; } exit: #ifdef WITH_OPENSSL if (rsa != NULL) RSA_free(rsa); #endif if (address != NULL) free(address); return retval; } poc-0.4.2/bv.h0000664000175000001440000000073610210123147013515 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef BV_H__ #define BV_H__ /*M \emph{Bit vector structure.} **/ typedef struct bv_s { /*@dependent@*/ unsigned char *data; unsigned int len; unsigned int idx; } bv_t; /*C **/ void bv_init(/*@out@*/ bv_t *bv, unsigned char *data, unsigned int len); void bv_reset(/*@out@*/ bv_t *bv); unsigned long bv_get_bits(bv_t *bv, unsigned int numbits); int bv_put_bits(bv_t *bv, unsigned long bits, unsigned int numbits); #endif /* BV_H__ */ poc-0.4.2/buf.c0000664000175000001440000000224610210123147013653 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include "buf.h" int buf_alloc(buf_t *buf, unsigned long size) { assert(buf != NULL); assert(size > 0); buf->data = malloc(size); if (buf->data != NULL) { buf->size = size; buf->len = 0; return 1; } else return 0; } int buf_grow(buf_t *buf) { assert(buf != NULL); assert(buf->size > 0); assert(buf->data != NULL); assert(buf->len <= buf->size); void *new = realloc(buf->data, buf->size * 2); if (new != NULL) { buf->data = new; buf->size *= 2; return 1; } else return 0; } int buf_append(buf_t *buf, void *data, unsigned long len) { assert(buf != NULL); assert(buf->data != NULL); assert(data != NULL); assert(len > 0); again: if ((buf->len + len) > buf->size) { if (!buf_grow(buf)) return 0; else goto again; } memcpy(buf->data + buf->len, data, len); buf->len += len; return 1; } void buf_free(buf_t *buf) { assert(buf != NULL); assert(buf->size > 0); assert(buf->data != NULL); free(buf->data); buf->size = 0; buf->len = 0; buf->data = NULL; } /*C **/ poc-0.4.2/ogg.c0000664000175000001440000000272410210123147013654 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include "buf.h" #include "ogg.h" #include "crc32.h" #include "pack.h" crc32_t ogg_crc32; void ogg_init(void) { crc32_init(&ogg_crc32, OGG_CRC32_POLY, 0, 0); } void ogg_page_init(ogg_page_t *page) { assert(page != NULL); page->raw.size = 0; page->raw.data = NULL; page->page_segments = 0; page->page_no = 0; page->stream = 0; page->page_cksum = 0; buf_alloc(&page->raw, 4000); assert(page->raw.data != NULL); page->size = 0; } void ogg_page_destroy(ogg_page_t *page) { assert(page != NULL); buf_free(&page->raw); } /* XXX make pointer array? */ unsigned char *ogg_segment(ogg_page_t *page, int num) { assert(page != NULL); if (num > page->page_segments) return NULL; unsigned char *res = page->raw.data + OGG_HDR_MIN_SIZE + page->page_segments; int i; for (i = 0; i < num; i++) res += page->lacing_values[i]; return res; } /*M \emph{Converts a sample position in an OGG page to a number in msecs.} **/ unsigned long ogg_position_to_msecs(ogg_page_t *page, unsigned long sample_rate) { assert(page != NULL); unsigned char *ptr = page->position; unsigned long position[2]; position[0] = LE_UINT32_UNPACK(ptr); position[1] = LE_UINT32_UNPACK(ptr); double dmsecs = (position[0] + position[1] * 2147483648.0) / (sample_rate / 1000.0); return (unsigned long)dmsecs; } /*C **/ poc-0.4.2/huffman-read.c0000664000175000001440000027730710204451551015456 0ustar manuelusers00000000000000#include "bv.h" /*@+charint@*/ typedef struct { unsigned char hlen; unsigned char code; } huffman_code_t; typedef struct { const short *tree; /* decoding tree */ const huffman_code_t *tab; /* coding table */ const unsigned short linbits; } huffman_tbl_t; static const short tree0[] = { 0 }; static const huffman_code_t tab0[] = { {0, 0} }; static const short tree1[] = { -5, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab1[] = { {1, 1}, {3, 1}, {2, 1}, {3, 0} }; static const short tree2[] = { -15, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 17, -1, 1, 16, 0 }; static const huffman_code_t tab2[] = { {1, 1}, {3, 2}, {6, 1}, {3, 3}, {3, 1}, {5, 1}, {5, 3}, {5, 2}, {6, 0} }; static const short tree3[] = { -13, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 16, 17, -1, 1, 0 }; static const huffman_code_t tab3[] = { {2, 3}, {2, 2}, {6, 1}, {3, 1}, {2, 1}, {5, 1}, {5, 3}, {5, 2}, {6, 0} }; static const short tree4[] = { 0 }; static const huffman_code_t tab4[] = { {0, 0} }; static const short tree5[] = { -29, -25, -23, -15, -7, -5, -3, -1, 51, 35, 50, 49, -3, -1, 19, 3, -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, 17, -1, 1, 16, 0 }; static const huffman_code_t tab5[] = { {1, 1}, {3, 2}, {6, 6}, {7, 5}, {3, 3}, {3, 1}, {6, 4}, {7, 4}, {6, 7}, {6, 5}, {7, 7}, {8, 1}, {7, 6}, {6, 1}, {7, 1}, {8, 0} }; static const short tree6[] = { -25, -19, -13, -9, -5, -3, -1, 51, 3, 35, -1, 50, 48, -1, 19, 49, -3, -1, 34, 2, 18, -3, -1, 33, 32, 1, -1, 17, -1, 16, 0 }; static const huffman_code_t tab6[] = { {3, 7}, {3, 3}, {5, 5}, {7, 1}, {3, 6}, {2, 2}, {4, 3}, {5, 2}, {4, 5}, {4, 4}, {5, 4}, {6, 1}, {6, 3}, {5, 3}, {6, 2}, {7, 0} }; static const short tree7[] = { -69, -65, -57, -39, -29, -17, -11, -7, -3, -1, 85, 69, -1, 84, 83, -1, 53, 68, -3, -1, 37, 82, 21, -5, -1, 81, -1, 5, 52, -1, 80, -1, 67, 51, -5, -3, -1, 36, 66, 20, -1, 65, 64, -11, -7, -3, -1, 4, 35, -1, 50, 3, -1, 19, 49, -3, -1, 48, 34, 18, -5, -1, 33, -1, 2, 32, 17, -1, 1, 16, 0 }; static const huffman_code_t tab7[] = { {1, 1}, {3, 2}, {6, 10}, {8, 19}, {8, 16}, {9, 10}, {3, 3}, {4, 3}, {6, 7}, {7, 10}, {7, 5}, {8, 3}, {6, 11}, {5, 4}, {7, 13}, {8, 17}, {8, 8}, {9, 4}, {7, 12}, {7, 11}, {8, 18}, {9, 15}, {9, 11}, {9, 2}, {7, 7}, {7, 6}, {8, 9}, {9, 14}, {9, 3}, {10, 1}, {8, 6}, {8, 4}, {9, 5}, {10, 3}, {10, 2}, {10, 0} }; static const short tree8[] = { -65, -63, -59, -45, -31, -19, -13, -7, -5, -3, -1, 85, 84, 69, 83, -3, -1, 53, 68, 37, -3, -1, 82, 5, 21, -5, -1, 81, -1, 52, 67, -3, -1, 80, 51, 36, -5, -3, -1, 66, 20, 65, -3, -1, 4, 64, -1, 35, 50, -9, -7, -3, -1, 19, 49, -1, 3, 48, 34, -1, 2, 32, -1, 18, 33, 17, -3, -1, 1, 16, 0 }; static const huffman_code_t tab8[] = { {2, 3}, {3, 4}, {6, 6}, {8, 18}, {8, 12}, {9, 5}, {3, 5}, {2, 1}, {4, 2}, {8, 16}, {8, 9}, {8, 3}, {6, 7}, {4, 3}, {6, 5}, {8, 14}, {8, 7}, {9, 3}, {8, 19}, {8, 17}, {8, 15}, {9, 13}, {9, 10}, {10, 4}, {8, 13}, {7, 5}, {8, 8}, {9, 11}, {10, 5}, {10, 1}, {9, 12}, {8, 4}, {9, 4}, {9, 1}, {11, 1}, {11, 0} }; static const short tree9[] = { -63, -53, -41, -29, -19, -11, -5, -3, -1, 85, 69, 53, -1, 83, -1, 84, 5, -3, -1, 68, 37, -1, 82, 21, -3, -1, 81, 52, -1, 67, -1, 80, 4, -7, -3, -1, 36, 66, -1, 51, 64, -1, 20, 65, -5, -3, -1, 35, 50, 19, -1, 49, -1, 3, 48, -5, -3, -1, 34, 2, 18, -1, 33, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab9[] = { {3, 7}, {3, 5}, {5, 9}, {6, 14}, {8, 15}, {9, 7}, {3, 6}, {3, 4}, {4, 5}, {5, 5}, {6, 6}, {8, 7}, {4, 7}, {4, 6}, {5, 8}, {6, 8}, {7, 8}, {8, 5}, {6, 15}, {5, 6}, {6, 9}, {7, 10}, {7, 5}, {8, 1}, {7, 11}, {6, 7}, {7, 9}, {7, 6}, {8, 4}, {9, 1}, {8, 14}, {7, 4}, {8, 6}, {8, 2}, {9, 6}, {9, 0} }; static const short tree10[] = { -125, -121, -111, -83, -55, -35, -21, -13, -7, -3, -1, 119, 103, -1, 118, 87, -3, -1, 117, 102, 71, -3, -1, 116, 86, -1, 101, 55, -9, -3, -1, 115, 70, -3, -1, 85, 84, 99, -1, 39, 114, -11, -5, -3, -1, 100, 7, 112, -1, 98, -1, 69, 53, -5, -1, 6, -1, 83, 68, 23, -17, -5, -1, 113, -1, 54, 38, -5, -3, -1, 37, 82, 21, -1, 81, -1, 52, 67, -3, -1, 22, 97, -1, 96, -1, 5, 80, -19, -11, -7, -3, -1, 36, 66, -1, 51, 4, -1, 20, 65, -3, -1, 64, 35, -1, 50, 3, -3, -1, 19, 49, -1, 48, 34, -7, -3, -1, 18, 33, -1, 2, 32, 17, -1, 1, 16, 0 }; static const huffman_code_t tab10[] = { {1, 1}, {3, 2}, {6, 10}, {8, 23}, {9, 35}, {9, 30}, {9, 12}, {10, 17}, {3, 3}, {4, 3}, {6, 8}, {7, 12}, {8, 18}, {9, 21}, {8, 12}, {8, 7}, {6, 11}, {6, 9}, {7, 15}, {8, 21}, {9, 32}, {10, 40}, {9, 19}, {9, 6}, {7, 14}, {7, 13}, {8, 22}, {9, 34}, {10, 46}, {10, 23}, {9, 18}, {10, 7}, {8, 20}, {8, 19}, {9, 33}, {10, 47}, {10, 27}, {10, 22}, {10, 9}, {10, 3}, {9, 31}, {9, 22}, {10, 41}, {10, 26}, {11, 21}, {11, 20}, {10, 5}, {11, 3}, {8, 14}, {8, 13}, {9, 10}, {10, 11}, {10, 16}, {10, 6}, {11, 5}, {11, 1}, {9, 9}, {8, 8}, {9, 7}, {10, 8}, {10, 4}, {11, 4}, {11, 2}, {11, 0} }; static const short tree11[] = { -121, -113, -89, -59, -43, -27, -17, -7, -3, -1, 119, 103, -1, 118, 117, -3, -1, 102, 71, -1, 116, -1, 87, 85, -5, -3, -1, 86, 101, 55, -1, 115, 70, -9, -7, -3, -1, 69, 84, -1, 53, 83, 39, -1, 114, -1, 100, 7, -5, -1, 113, -1, 23, 112, -3, -1, 54, 99, -1, 96, -1, 68, 37, -13, -7, -5, -3, -1, 82, 5, 21, 98, -3, -1, 38, 6, 22, -5, -1, 97, -1, 81, 52, -5, -1, 80, -1, 67, 51, -1, 36, 66, -15, -11, -7, -3, -1, 20, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -5, -3, -1, 3, 48, 34, 33, -5, -1, 18, -1, 2, 32, 17, -3, -1, 1, 16, 0 }; static const huffman_code_t tab11[] = { {2, 3}, {3, 4}, {5, 10}, {7, 24}, {8, 34}, {9, 33}, {8, 21}, {9, 15}, {3, 5}, {3, 3}, {4, 4}, {6, 10}, {8, 32}, {8, 17}, {7, 11}, {8, 10}, {5, 11}, {5, 7}, {6, 13}, {7, 18}, {8, 30}, {9, 31}, {8, 20}, {8, 5}, {7, 25}, {6, 11}, {7, 19}, {9, 59}, {8, 27}, {10, 18}, {8, 12}, {9, 5}, {8, 35}, {8, 33}, {8, 31}, {9, 58}, {9, 30}, {10, 16}, {9, 7}, {10, 5}, {8, 28}, {8, 26}, {9, 32}, {10, 19}, {10, 17}, {11, 15}, {10, 8}, {11, 14}, {8, 14}, {7, 12}, {7, 9}, {8, 13}, {9, 14}, {10, 9}, {10, 4}, {10, 1}, {8, 11}, {7, 4}, {8, 6}, {9, 6}, {10, 6}, {10, 3}, {10, 2}, {10, 0} }; static const short tree12[] = { -115, -99, -73, -45, -27, -17, -9, -5, -3, -1, 119, 103, 118, -1, 87, 117, -3, -1, 102, 71, -1, 116, 101, -3, -1, 86, 55, -3, -1, 115, 85, 39, -7, -3, -1, 114, 70, -1, 100, 23, -5, -1, 113, -1, 7, 112, -1, 54, 99, -13, -9, -3, -1, 69, 84, -1, 68, -1, 6, 5, -1, 38, 98, -5, -1, 97, -1, 22, 96, -3, -1, 53, 83, -1, 37, 82, -17, -7, -3, -1, 21, 81, -1, 52, 67, -5, -3, -1, 80, 4, 36, -1, 66, 20, -3, -1, 51, 65, -1, 35, 50, -11, -7, -5, -3, -1, 64, 3, 48, 19, -1, 49, 34, -1, 18, 33, -7, -5, -3, -1, 2, 32, 0, 17, -1, 1, 16 }; static const huffman_code_t tab12[] = { {4, 9}, {3, 6}, {5, 16}, {7, 33}, {8, 41}, {9, 39}, {9, 38}, {9, 26}, {3, 7}, {3, 5}, {4, 6}, {5, 9}, {7, 23}, {7, 16}, {8, 26}, {8, 11}, {5, 17}, {4, 7}, {5, 11}, {6, 14}, {7, 21}, {8, 30}, {7, 10}, {8, 7}, {6, 17}, {5, 10}, {6, 15}, {6, 12}, {7, 18}, {8, 28}, {8, 14}, {8, 5}, {7, 32}, {6, 13}, {7, 22}, {7, 19}, {8, 18}, {8, 16}, {8, 9}, {9, 5}, {8, 40}, {7, 17}, {8, 31}, {8, 29}, {8, 17}, {9, 13}, {8, 4}, {9, 2}, {8, 27}, {7, 12}, {7, 11}, {8, 15}, {8, 10}, {9, 7}, {9, 4}, {10, 1}, {9, 27}, {8, 12}, {8, 8}, {9, 12}, {9, 6}, {9, 3}, {9, 1}, {10, 0} }; static const short tree13[] = { -509, -503, -475, -405, -333, -265, -205, -153, -115, -83, -53, -35, -21, -13, -9, -7, -5, -3, -1, 254, 252, 253, 237, 255, -1, 239, 223, -3, -1, 238, 207, -1, 222, 191, -9, -3, -1, 251, 206, -1, 220, -1, 175, 233, -1, 236, 221, -9, -5, -3, -1, 250, 205, 190, -1, 235, 159, -3, -1, 249, 234, -1, 189, 219, -17, -9, -3, -1, 143, 248, -1, 204, -1, 174, 158, -5, -1, 142, -1, 127, 126, 247, -5, -1, 218, -1, 173, 188, -3, -1, 203, 246, 111, -15, -7, -3, -1, 232, 95, -1, 157, 217, -3, -1, 245, 231, -1, 172, 187, -9, -3, -1, 79, 244, -3, -1, 202, 230, 243, -1, 63, -1, 141, 216, -21, -9, -3, -1, 47, 242, -3, -1, 110, 156, 15, -5, -3, -1, 201, 94, 171, -3, -1, 125, 215, 78, -11, -5, -3, -1, 200, 214, 62, -1, 185, -1, 155, 170, -1, 31, 241, -23, -13, -5, -1, 240, -1, 186, 229, -3, -1, 228, 140, -1, 109, 227, -5, -1, 226, -1, 46, 14, -1, 30, 225, -15, -7, -3, -1, 224, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -7, -3, -1, 212, 154, -1, 169, 108, -1, 198, 61, -37, -21, -9, -5, -3, -1, 211, 123, 45, -1, 210, 29, -5, -1, 183, -1, 92, 197, -3, -1, 153, 122, 195, -7, -5, -3, -1, 167, 151, 75, 209, -3, -1, 13, 208, -1, 138, 168, -11, -7, -3, -1, 76, 196, -1, 107, 182, -1, 60, 44, -3, -1, 194, 91, -3, -1, 181, 137, 28, -43, -23, -11, -5, -1, 193, -1, 152, 12, -1, 192, -1, 180, 106, -5, -3, -1, 166, 121, 59, -1, 179, -1, 136, 90, -11, -5, -1, 43, -1, 165, 105, -1, 164, -1, 120, 135, -5, -1, 148, -1, 119, 118, 178, -11, -3, -1, 27, 177, -3, -1, 11, 176, -1, 150, 74, -7, -3, -1, 58, 163, -1, 89, 149, -1, 42, 162, -47, -23, -9, -3, -1, 26, 161, -3, -1, 10, 104, 160, -5, -3, -1, 134, 73, 147, -3, -1, 57, 88, -1, 133, 103, -9, -3, -1, 41, 146, -3, -1, 87, 117, 56, -5, -1, 131, -1, 102, 71, -3, -1, 116, 86, -1, 101, 115, -11, -3, -1, 25, 145, -3, -1, 9, 144, -1, 72, 132, -7, -5, -1, 114, -1, 70, 100, 40, -1, 130, 24, -41, -27, -11, -5, -3, -1, 55, 39, 23, -1, 113, -1, 85, 7, -7, -3, -1, 112, 54, -1, 99, 69, -3, -1, 84, 38, -1, 98, 53, -5, -1, 129, -1, 8, 128, -3, -1, 22, 97, -1, 6, 96, -13, -9, -5, -3, -1, 83, 68, 37, -1, 82, 5, -1, 21, 81, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -19, -11, -5, -1, 65, -1, 4, 64, -3, -1, 35, 50, 19, -3, -1, 49, 3, -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab13[] = { {1, 1}, {4, 5}, {6, 14}, {7, 21}, {8, 34}, {9, 51}, {9, 46}, {10, 71}, {9, 42}, {10, 52}, {11, 68}, {11, 52}, {12, 67}, {12, 44}, {13, 43}, {13, 19}, {3, 3}, {4, 4}, {6, 12}, {7, 19}, {8, 31}, {8, 26}, {9, 44}, {9, 33}, {9, 31}, {9, 24}, {10, 32}, {10, 24}, {11, 31}, {12, 35}, {12, 22}, {12, 14}, {6, 15}, {6, 13}, {7, 23}, {8, 36}, {9, 59}, {9, 49}, {10, 77}, {10, 65}, {9, 29}, {10, 40}, {10, 30}, {11, 40}, {11, 27}, {12, 33}, {13, 42}, {13, 16}, {7, 22}, {7, 20}, {8, 37}, {9, 61}, {9, 56}, {10, 79}, {10, 73}, {10, 64}, {10, 43}, {11, 76}, {11, 56}, {11, 37}, {11, 26}, {12, 31}, {13, 25}, {13, 14}, {8, 35}, {7, 16}, {9, 60}, {9, 57}, {10, 97}, {10, 75}, {11, 114}, {11, 91}, {10, 54}, {11, 73}, {11, 55}, {12, 41}, {12, 48}, {13, 53}, {13, 23}, {14, 24}, {9, 58}, {8, 27}, {9, 50}, {10, 96}, {10, 76}, {10, 70}, {11, 93}, {11, 84}, {11, 77}, {11, 58}, {12, 79}, {11, 29}, {13, 74}, {13, 49}, {14, 41}, {14, 17}, {9, 47}, {9, 45}, {10, 78}, {10, 74}, {11, 115}, {11, 94}, {11, 90}, {11, 79}, {11, 69}, {12, 83}, {12, 71}, {12, 50}, {13, 59}, {13, 38}, {14, 36}, {14, 15}, {10, 72}, {9, 34}, {10, 56}, {11, 95}, {11, 92}, {11, 85}, {12, 91}, {12, 90}, {12, 86}, {12, 73}, {13, 77}, {13, 65}, {13, 51}, {14, 44}, {16, 43}, {16, 42}, {9, 43}, {8, 20}, {9, 30}, {10, 44}, {10, 55}, {11, 78}, {11, 72}, {12, 87}, {12, 78}, {12, 61}, {12, 46}, {13, 54}, {13, 37}, {14, 30}, {15, 20}, {15, 16}, {10, 53}, {9, 25}, {10, 41}, {10, 37}, {11, 44}, {11, 59}, {11, 54}, {13, 81}, {12, 66}, {13, 76}, {13, 57}, {14, 54}, {14, 37}, {14, 18}, {16, 39}, {15, 11}, {10, 35}, {10, 33}, {10, 31}, {11, 57}, {11, 42}, {12, 82}, {12, 72}, {13, 80}, {12, 47}, {13, 58}, {14, 55}, {13, 21}, {14, 22}, {15, 26}, {16, 38}, {17, 22}, {11, 53}, {10, 25}, {10, 23}, {11, 38}, {12, 70}, {12, 60}, {12, 51}, {12, 36}, {13, 55}, {13, 26}, {13, 34}, {14, 23}, {15, 27}, {15, 14}, {15, 9}, {16, 7}, {11, 34}, {11, 32}, {11, 28}, {12, 39}, {12, 49}, {13, 75}, {12, 30}, {13, 52}, {14, 48}, {14, 40}, {15, 52}, {15, 28}, {15, 18}, {16, 17}, {16, 9}, {16, 5}, {12, 45}, {11, 21}, {12, 34}, {13, 64}, {13, 56}, {13, 50}, {14, 49}, {14, 45}, {14, 31}, {14, 19}, {14, 12}, {15, 15}, {16, 10}, {15, 7}, {16, 6}, {16, 3}, {13, 48}, {12, 23}, {12, 20}, {13, 39}, {13, 36}, {13, 35}, {15, 53}, {14, 21}, {14, 16}, {17, 23}, {15, 13}, {15, 10}, {15, 6}, {17, 1}, {16, 4}, {16, 2}, {12, 16}, {12, 15}, {13, 17}, {14, 27}, {14, 25}, {14, 20}, {15, 29}, {14, 11}, {15, 17}, {15, 12}, {16, 16}, {16, 8}, {19, 1}, {18, 1}, {19, 0}, {16, 1} }; static const short tree14[] = { 0 }; static const huffman_code_t tab14[] = { {0, 0} }; static const short tree15[] = { -495, -445, -355, -263, -183, -115, -77, -43, -27, -13, -7, -3, -1, 255, 239, -1, 254, 223, -1, 238, -1, 253, 207, -7, -3, -1, 252, 222, -1, 237, 191, -1, 251, -1, 206, 236, -7, -3, -1, 221, 175, -1, 250, 190, -3, -1, 235, 205, -1, 220, 159, -15, -7, -3, -1, 249, 234, -1, 189, 219, -3, -1, 143, 248, -1, 204, 158, -7, -3, -1, 233, 127, -1, 247, 173, -3, -1, 218, 188, -1, 111, -1, 174, 15, -19, -11, -3, -1, 203, 246, -3, -1, 142, 232, -1, 95, 157, -3, -1, 245, 126, -1, 231, 172, -9, -3, -1, 202, 187, -3, -1, 217, 141, 79, -3, -1, 244, 63, -1, 243, 216, -33, -17, -9, -3, -1, 230, 47, -1, 242, -1, 110, 240, -3, -1, 31, 241, -1, 156, 201, -7, -3, -1, 94, 171, -1, 186, 229, -3, -1, 125, 215, -1, 78, 228, -15, -7, -3, -1, 140, 200, -1, 62, 109, -3, -1, 214, 227, -1, 155, 185, -7, -3, -1, 46, 170, -1, 226, 30, -5, -1, 225, -1, 14, 224, -1, 93, 213, -45, -25, -13, -7, -3, -1, 124, 199, -1, 77, 139, -1, 212, -1, 184, 154, -7, -3, -1, 169, 108, -1, 198, 61, -1, 211, 210, -9, -5, -3, -1, 45, 13, 29, -1, 123, 183, -5, -1, 209, -1, 92, 208, -1, 197, 138, -17, -7, -3, -1, 168, 76, -1, 196, 107, -5, -1, 182, -1, 153, 12, -1, 60, 195, -9, -3, -1, 122, 167, -1, 166, -1, 192, 11, -1, 194, -1, 44, 91, -55, -29, -15, -7, -3, -1, 181, 28, -1, 137, 152, -3, -1, 193, 75, -1, 180, 106, -5, -3, -1, 59, 121, 179, -3, -1, 151, 136, -1, 43, 90, -11, -5, -1, 178, -1, 165, 27, -1, 177, -1, 176, 105, -7, -3, -1, 150, 74, -1, 164, 120, -3, -1, 135, 58, 163, -17, -7, -3, -1, 89, 149, -1, 42, 162, -3, -1, 26, 161, -3, -1, 10, 160, 104, -7, -3, -1, 134, 73, -1, 148, 57, -5, -1, 147, -1, 119, 9, -1, 88, 133, -53, -29, -13, -7, -3, -1, 41, 103, -1, 118, 146, -1, 145, -1, 25, 144, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 71, -7, -3, -1, 40, 130, -1, 24, 129, -7, -3, -1, 116, 8, -1, 128, 86, -3, -1, 101, 55, -1, 115, 70, -17, -7, -3, -1, 39, 114, -1, 100, 23, -3, -1, 85, 113, -3, -1, 7, 112, 54, -7, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -3, -1, 6, 96, 53, -33, -19, -9, -5, -1, 97, -1, 83, 68, -1, 37, 82, -3, -1, 21, 81, -3, -1, 5, 80, 52, -7, -3, -1, 67, 36, -1, 66, 51, -1, 65, -1, 20, 4, -9, -3, -1, 35, 50, -3, -1, 64, 3, 19, -3, -1, 49, 48, 34, -9, -7, -3, -1, 18, 33, -1, 2, 32, 17, -3, -1, 1, 16, 0 }; static const huffman_code_t tab15[] = { {3, 7}, {4, 12}, {5, 18}, {7, 53}, {7, 47}, {8, 76}, {9, 124}, {9, 108}, {9, 89}, {10, 123}, {10, 108}, {11, 119}, {11, 107}, {11, 81}, {12, 122}, {13, 63}, {4, 13}, {3, 5}, {5, 16}, {6, 27}, {7, 46}, {7, 36}, {8, 61}, {8, 51}, {8, 42}, {9, 70}, {9, 52}, {10, 83}, {10, 65}, {10, 41}, {11, 59}, {11, 36}, {5, 19}, {5, 17}, {5, 15}, {6, 24}, {7, 41}, {7, 34}, {8, 59}, {8, 48}, {8, 40}, {9, 64}, {9, 50}, {10, 78}, {10, 62}, {11, 80}, {11, 56}, {11, 33}, {6, 29}, {6, 28}, {6, 25}, {7, 43}, {7, 39}, {8, 63}, {8, 55}, {9, 93}, {9, 76}, {9, 59}, {10, 93}, {10, 72}, {10, 54}, {11, 75}, {11, 50}, {11, 29}, {7, 52}, {6, 22}, {7, 42}, {7, 40}, {8, 67}, {8, 57}, {9, 95}, {9, 79}, {9, 72}, {9, 57}, {10, 89}, {10, 69}, {10, 49}, {11, 66}, {11, 46}, {11, 27}, {8, 77}, {7, 37}, {7, 35}, {8, 66}, {8, 58}, {8, 52}, {9, 91}, {9, 74}, {9, 62}, {9, 48}, {10, 79}, {10, 63}, {11, 90}, {11, 62}, {11, 40}, {12, 38}, {9, 125}, {7, 32}, {8, 60}, {8, 56}, {8, 50}, {9, 92}, {9, 78}, {9, 65}, {9, 55}, {10, 87}, {10, 71}, {10, 51}, {11, 73}, {11, 51}, {12, 70}, {12, 30}, {9, 109}, {8, 53}, {8, 49}, {9, 94}, {9, 88}, {9, 75}, {9, 66}, {10, 122}, {10, 91}, {10, 73}, {10, 56}, {10, 42}, {11, 64}, {11, 44}, {11, 21}, {12, 25}, {9, 90}, {8, 43}, {8, 41}, {9, 77}, {9, 73}, {9, 63}, {9, 56}, {10, 92}, {10, 77}, {10, 66}, {10, 47}, {11, 67}, {11, 48}, {12, 53}, {12, 36}, {12, 20}, {9, 71}, {8, 34}, {9, 67}, {9, 60}, {9, 58}, {9, 49}, {10, 88}, {10, 76}, {10, 67}, {11, 106}, {11, 71}, {11, 54}, {11, 38}, {12, 39}, {12, 23}, {12, 15}, {10, 109}, {9, 53}, {9, 51}, {9, 47}, {10, 90}, {10, 82}, {10, 58}, {10, 57}, {10, 48}, {11, 72}, {11, 57}, {11, 41}, {11, 23}, {12, 27}, {13, 62}, {12, 9}, {10, 86}, {9, 42}, {9, 40}, {9, 37}, {10, 70}, {10, 64}, {10, 52}, {10, 43}, {11, 70}, {11, 55}, {11, 42}, {11, 25}, {12, 29}, {12, 18}, {12, 11}, {13, 11}, {11, 118}, {10, 68}, {9, 30}, {10, 55}, {10, 50}, {10, 46}, {11, 74}, {11, 65}, {11, 49}, {11, 39}, {11, 24}, {11, 16}, {12, 22}, {12, 13}, {13, 14}, {13, 7}, {11, 91}, {10, 44}, {10, 39}, {10, 38}, {10, 34}, {11, 63}, {11, 52}, {11, 45}, {11, 31}, {12, 52}, {12, 28}, {12, 19}, {12, 14}, {12, 8}, {13, 9}, {13, 3}, {12, 123}, {11, 60}, {11, 58}, {11, 53}, {11, 47}, {11, 43}, {11, 32}, {11, 22}, {12, 37}, {12, 24}, {12, 17}, {12, 12}, {13, 15}, {13, 10}, {12, 2}, {13, 1}, {12, 71}, {11, 37}, {11, 34}, {11, 30}, {11, 28}, {11, 20}, {11, 17}, {12, 26}, {12, 21}, {12, 16}, {12, 10}, {12, 6}, {13, 8}, {13, 6}, {13, 2}, {13, 0} }; static const short tree16[] = { -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab16[] = { {1, 1}, {4, 5}, {6, 14}, {8, 44}, {9, 74}, {9, 63}, {10, 110}, {10, 93}, {11, 172}, {11, 149}, {11, 138}, {12, 242}, {12, 225}, {12, 195}, {13, 120}, {9, 17}, {3, 3}, {4, 4}, {6, 12}, {7, 20}, {8, 35}, {9, 62}, {9, 53}, {9, 47}, {10, 83}, {10, 75}, {10, 68}, {11, 119}, {12, 201}, {11, 107}, {12, 207}, {8, 9}, {6, 15}, {6, 13}, {7, 23}, {8, 38}, {9, 67}, {9, 58}, {10, 103}, {10, 90}, {11, 161}, {10, 72}, {11, 127}, {11, 117}, {11, 110}, {12, 209}, {12, 206}, {9, 16}, {8, 45}, {7, 21}, {8, 39}, {9, 69}, {9, 64}, {10, 114}, {10, 99}, {10, 87}, {11, 158}, {11, 140}, {12, 252}, {12, 212}, {12, 199}, {13, 131}, {13, 109}, {10, 26}, {9, 75}, {8, 36}, {9, 68}, {9, 65}, {10, 115}, {10, 101}, {11, 179}, {11, 164}, {11, 155}, {12, 8}, {12, 246}, {12, 226}, {13, 139}, {13, 126}, {13, 106}, {9, 9}, {9, 66}, {8, 30}, {9, 59}, {9, 56}, {10, 102}, {11, 185}, {11, 173}, {12, 9}, {11, 142}, {12, 253}, {12, 232}, {13, 144}, {13, 132}, {13, 122}, {14, 189}, {10, 16}, {10, 111}, {9, 54}, {9, 52}, {10, 100}, {11, 184}, {11, 178}, {11, 160}, {11, 133}, {12, 1}, {12, 244}, {12, 228}, {12, 217}, {13, 129}, {13, 110}, {14, 203}, {10, 10}, {10, 98}, {9, 48}, {10, 91}, {10, 88}, {11, 165}, {11, 157}, {11, 148}, {12, 5}, {12, 248}, {13, 151}, {13, 141}, {13, 116}, {13, 124}, {15, 121}, {15, 116}, {10, 8}, {10, 85}, {10, 84}, {10, 81}, {11, 159}, {11, 156}, {11, 143}, {12, 4}, {12, 249}, {13, 171}, {13, 145}, {13, 136}, {13, 127}, {14, 215}, {14, 201}, {14, 196}, {10, 7}, {11, 154}, {10, 76}, {10, 73}, {11, 141}, {11, 131}, {12, 0}, {12, 245}, {13, 170}, {13, 150}, {13, 138}, {13, 128}, {14, 223}, {13, 103}, {14, 198}, {13, 96}, {11, 11}, {11, 139}, {11, 129}, {10, 67}, {11, 125}, {12, 247}, {12, 233}, {12, 229}, {12, 219}, {13, 137}, {14, 231}, {14, 225}, {14, 208}, {15, 117}, {15, 114}, {14, 183}, {10, 4}, {12, 243}, {11, 120}, {11, 118}, {11, 115}, {12, 227}, {12, 223}, {13, 140}, {14, 234}, {14, 230}, {14, 224}, {14, 209}, {14, 200}, {14, 194}, {13, 223}, {14, 180}, {11, 6}, {12, 202}, {12, 224}, {12, 222}, {12, 218}, {12, 216}, {13, 133}, {13, 130}, {13, 125}, {13, 108}, {15, 120}, {14, 187}, {14, 195}, {14, 184}, {14, 181}, {16, 192}, {11, 4}, {14, 235}, {12, 211}, {12, 210}, {12, 208}, {13, 114}, {13, 123}, {14, 222}, {14, 211}, {14, 202}, {16, 199}, {15, 115}, {15, 109}, {15, 108}, {17, 131}, {15, 97}, {11, 2}, {13, 121}, {13, 113}, {11, 102}, {12, 187}, {14, 214}, {14, 210}, {13, 102}, {14, 199}, {14, 197}, {15, 98}, {16, 198}, {15, 103}, {17, 130}, {15, 102}, {14, 178}, {11, 0}, {9, 12}, {8, 10}, {8, 7}, {9, 11}, {9, 10}, {10, 17}, {10, 11}, {10, 9}, {11, 13}, {11, 12}, {11, 10}, {11, 7}, {11, 5}, {11, 3}, {11, 1}, {8, 3} }; static const short tree17[] = { -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab17[] = { {1, 1}, {4, 5}, {6, 14}, {8, 44}, {9, 74}, {9, 63}, {10, 110}, {10, 93}, {11, 172}, {11, 149}, {11, 138}, {12, 242}, {12, 225}, {12, 195}, {13, 120}, {9, 17}, {3, 3}, {4, 4}, {6, 12}, {7, 20}, {8, 35}, {9, 62}, {9, 53}, {9, 47}, {10, 83}, {10, 75}, {10, 68}, {11, 119}, {12, 201}, {11, 107}, {12, 207}, {8, 9}, {6, 15}, {6, 13}, {7, 23}, {8, 38}, {9, 67}, {9, 58}, {10, 103}, {10, 90}, {11, 161}, {10, 72}, {11, 127}, {11, 117}, {11, 110}, {12, 209}, {12, 206}, {9, 16}, {8, 45}, {7, 21}, {8, 39}, {9, 69}, {9, 64}, {10, 114}, {10, 99}, {10, 87}, {11, 158}, {11, 140}, {12, 252}, {12, 212}, {12, 199}, {13, 131}, {13, 109}, {10, 26}, {9, 75}, {8, 36}, {9, 68}, {9, 65}, {10, 115}, {10, 101}, {11, 179}, {11, 164}, {11, 155}, {12, 8}, {12, 246}, {12, 226}, {13, 139}, {13, 126}, {13, 106}, {9, 9}, {9, 66}, {8, 30}, {9, 59}, {9, 56}, {10, 102}, {11, 185}, {11, 173}, {12, 9}, {11, 142}, {12, 253}, {12, 232}, {13, 144}, {13, 132}, {13, 122}, {14, 189}, {10, 16}, {10, 111}, {9, 54}, {9, 52}, {10, 100}, {11, 184}, {11, 178}, {11, 160}, {11, 133}, {12, 1}, {12, 244}, {12, 228}, {12, 217}, {13, 129}, {13, 110}, {14, 203}, {10, 10}, {10, 98}, {9, 48}, {10, 91}, {10, 88}, {11, 165}, {11, 157}, {11, 148}, {12, 5}, {12, 248}, {13, 151}, {13, 141}, {13, 116}, {13, 124}, {15, 121}, {15, 116}, {10, 8}, {10, 85}, {10, 84}, {10, 81}, {11, 159}, {11, 156}, {11, 143}, {12, 4}, {12, 249}, {13, 171}, {13, 145}, {13, 136}, {13, 127}, {14, 215}, {14, 201}, {14, 196}, {10, 7}, {11, 154}, {10, 76}, {10, 73}, {11, 141}, {11, 131}, {12, 0}, {12, 245}, {13, 170}, {13, 150}, {13, 138}, {13, 128}, {14, 223}, {13, 103}, {14, 198}, {13, 96}, {11, 11}, {11, 139}, {11, 129}, {10, 67}, {11, 125}, {12, 247}, {12, 233}, {12, 229}, {12, 219}, {13, 137}, {14, 231}, {14, 225}, {14, 208}, {15, 117}, {15, 114}, {14, 183}, {10, 4}, {12, 243}, {11, 120}, {11, 118}, {11, 115}, {12, 227}, {12, 223}, {13, 140}, {14, 234}, {14, 230}, {14, 224}, {14, 209}, {14, 200}, {14, 194}, {13, 223}, {14, 180}, {11, 6}, {12, 202}, {12, 224}, {12, 222}, {12, 218}, {12, 216}, {13, 133}, {13, 130}, {13, 125}, {13, 108}, {15, 120}, {14, 187}, {14, 195}, {14, 184}, {14, 181}, {16, 192}, {11, 4}, {14, 235}, {12, 211}, {12, 210}, {12, 208}, {13, 114}, {13, 123}, {14, 222}, {14, 211}, {14, 202}, {16, 199}, {15, 115}, {15, 109}, {15, 108}, {17, 131}, {15, 97}, {11, 2}, {13, 121}, {13, 113}, {11, 102}, {12, 187}, {14, 214}, {14, 210}, {13, 102}, {14, 199}, {14, 197}, {15, 98}, {16, 198}, {15, 103}, {17, 130}, {15, 102}, {14, 178}, {11, 0}, {9, 12}, {8, 10}, {8, 7}, {9, 11}, {9, 10}, {10, 17}, {10, 11}, {10, 9}, {11, 13}, {11, 12}, {11, 10}, {11, 7}, {11, 5}, {11, 3}, {11, 1}, {8, 3} }; static const short tree18[] = { -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab18[] = { {1, 1}, {4, 5}, {6, 14}, {8, 44}, {9, 74}, {9, 63}, {10, 110}, {10, 93}, {11, 172}, {11, 149}, {11, 138}, {12, 242}, {12, 225}, {12, 195}, {13, 120}, {9, 17}, {3, 3}, {4, 4}, {6, 12}, {7, 20}, {8, 35}, {9, 62}, {9, 53}, {9, 47}, {10, 83}, {10, 75}, {10, 68}, {11, 119}, {12, 201}, {11, 107}, {12, 207}, {8, 9}, {6, 15}, {6, 13}, {7, 23}, {8, 38}, {9, 67}, {9, 58}, {10, 103}, {10, 90}, {11, 161}, {10, 72}, {11, 127}, {11, 117}, {11, 110}, {12, 209}, {12, 206}, {9, 16}, {8, 45}, {7, 21}, {8, 39}, {9, 69}, {9, 64}, {10, 114}, {10, 99}, {10, 87}, {11, 158}, {11, 140}, {12, 252}, {12, 212}, {12, 199}, {13, 131}, {13, 109}, {10, 26}, {9, 75}, {8, 36}, {9, 68}, {9, 65}, {10, 115}, {10, 101}, {11, 179}, {11, 164}, {11, 155}, {12, 8}, {12, 246}, {12, 226}, {13, 139}, {13, 126}, {13, 106}, {9, 9}, {9, 66}, {8, 30}, {9, 59}, {9, 56}, {10, 102}, {11, 185}, {11, 173}, {12, 9}, {11, 142}, {12, 253}, {12, 232}, {13, 144}, {13, 132}, {13, 122}, {14, 189}, {10, 16}, {10, 111}, {9, 54}, {9, 52}, {10, 100}, {11, 184}, {11, 178}, {11, 160}, {11, 133}, {12, 1}, {12, 244}, {12, 228}, {12, 217}, {13, 129}, {13, 110}, {14, 203}, {10, 10}, {10, 98}, {9, 48}, {10, 91}, {10, 88}, {11, 165}, {11, 157}, {11, 148}, {12, 5}, {12, 248}, {13, 151}, {13, 141}, {13, 116}, {13, 124}, {15, 121}, {15, 116}, {10, 8}, {10, 85}, {10, 84}, {10, 81}, {11, 159}, {11, 156}, {11, 143}, {12, 4}, {12, 249}, {13, 171}, {13, 145}, {13, 136}, {13, 127}, {14, 215}, {14, 201}, {14, 196}, {10, 7}, {11, 154}, {10, 76}, {10, 73}, {11, 141}, {11, 131}, {12, 0}, {12, 245}, {13, 170}, {13, 150}, {13, 138}, {13, 128}, {14, 223}, {13, 103}, {14, 198}, {13, 96}, {11, 11}, {11, 139}, {11, 129}, {10, 67}, {11, 125}, {12, 247}, {12, 233}, {12, 229}, {12, 219}, {13, 137}, {14, 231}, {14, 225}, {14, 208}, {15, 117}, {15, 114}, {14, 183}, {10, 4}, {12, 243}, {11, 120}, {11, 118}, {11, 115}, {12, 227}, {12, 223}, {13, 140}, {14, 234}, {14, 230}, {14, 224}, {14, 209}, {14, 200}, {14, 194}, {13, 223}, {14, 180}, {11, 6}, {12, 202}, {12, 224}, {12, 222}, {12, 218}, {12, 216}, {13, 133}, {13, 130}, {13, 125}, {13, 108}, {15, 120}, {14, 187}, {14, 195}, {14, 184}, {14, 181}, {16, 192}, {11, 4}, {14, 235}, {12, 211}, {12, 210}, {12, 208}, {13, 114}, {13, 123}, {14, 222}, {14, 211}, {14, 202}, {16, 199}, {15, 115}, {15, 109}, {15, 108}, {17, 131}, {15, 97}, {11, 2}, {13, 121}, {13, 113}, {11, 102}, {12, 187}, {14, 214}, {14, 210}, {13, 102}, {14, 199}, {14, 197}, {15, 98}, {16, 198}, {15, 103}, {17, 130}, {15, 102}, {14, 178}, {11, 0}, {9, 12}, {8, 10}, {8, 7}, {9, 11}, {9, 10}, {10, 17}, {10, 11}, {10, 9}, {11, 13}, {11, 12}, {11, 10}, {11, 7}, {11, 5}, {11, 3}, {11, 1}, {8, 3} }; static const short tree19[] = { -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab19[] = { {1, 1}, {4, 5}, {6, 14}, {8, 44}, {9, 74}, {9, 63}, {10, 110}, {10, 93}, {11, 172}, {11, 149}, {11, 138}, {12, 242}, {12, 225}, {12, 195}, {13, 120}, {9, 17}, {3, 3}, {4, 4}, {6, 12}, {7, 20}, {8, 35}, {9, 62}, {9, 53}, {9, 47}, {10, 83}, {10, 75}, {10, 68}, {11, 119}, {12, 201}, {11, 107}, {12, 207}, {8, 9}, {6, 15}, {6, 13}, {7, 23}, {8, 38}, {9, 67}, {9, 58}, {10, 103}, {10, 90}, {11, 161}, {10, 72}, {11, 127}, {11, 117}, {11, 110}, {12, 209}, {12, 206}, {9, 16}, {8, 45}, {7, 21}, {8, 39}, {9, 69}, {9, 64}, {10, 114}, {10, 99}, {10, 87}, {11, 158}, {11, 140}, {12, 252}, {12, 212}, {12, 199}, {13, 131}, {13, 109}, {10, 26}, {9, 75}, {8, 36}, {9, 68}, {9, 65}, {10, 115}, {10, 101}, {11, 179}, {11, 164}, {11, 155}, {12, 8}, {12, 246}, {12, 226}, {13, 139}, {13, 126}, {13, 106}, {9, 9}, {9, 66}, {8, 30}, {9, 59}, {9, 56}, {10, 102}, {11, 185}, {11, 173}, {12, 9}, {11, 142}, {12, 253}, {12, 232}, {13, 144}, {13, 132}, {13, 122}, {14, 189}, {10, 16}, {10, 111}, {9, 54}, {9, 52}, {10, 100}, {11, 184}, {11, 178}, {11, 160}, {11, 133}, {12, 1}, {12, 244}, {12, 228}, {12, 217}, {13, 129}, {13, 110}, {14, 203}, {10, 10}, {10, 98}, {9, 48}, {10, 91}, {10, 88}, {11, 165}, {11, 157}, {11, 148}, {12, 5}, {12, 248}, {13, 151}, {13, 141}, {13, 116}, {13, 124}, {15, 121}, {15, 116}, {10, 8}, {10, 85}, {10, 84}, {10, 81}, {11, 159}, {11, 156}, {11, 143}, {12, 4}, {12, 249}, {13, 171}, {13, 145}, {13, 136}, {13, 127}, {14, 215}, {14, 201}, {14, 196}, {10, 7}, {11, 154}, {10, 76}, {10, 73}, {11, 141}, {11, 131}, {12, 0}, {12, 245}, {13, 170}, {13, 150}, {13, 138}, {13, 128}, {14, 223}, {13, 103}, {14, 198}, {13, 96}, {11, 11}, {11, 139}, {11, 129}, {10, 67}, {11, 125}, {12, 247}, {12, 233}, {12, 229}, {12, 219}, {13, 137}, {14, 231}, {14, 225}, {14, 208}, {15, 117}, {15, 114}, {14, 183}, {10, 4}, {12, 243}, {11, 120}, {11, 118}, {11, 115}, {12, 227}, {12, 223}, {13, 140}, {14, 234}, {14, 230}, {14, 224}, {14, 209}, {14, 200}, {14, 194}, {13, 223}, {14, 180}, {11, 6}, {12, 202}, {12, 224}, {12, 222}, {12, 218}, {12, 216}, {13, 133}, {13, 130}, {13, 125}, {13, 108}, {15, 120}, {14, 187}, {14, 195}, {14, 184}, {14, 181}, {16, 192}, {11, 4}, {14, 235}, {12, 211}, {12, 210}, {12, 208}, {13, 114}, {13, 123}, {14, 222}, {14, 211}, {14, 202}, {16, 199}, {15, 115}, {15, 109}, {15, 108}, {17, 131}, {15, 97}, {11, 2}, {13, 121}, {13, 113}, {11, 102}, {12, 187}, {14, 214}, {14, 210}, {13, 102}, {14, 199}, {14, 197}, {15, 98}, {16, 198}, {15, 103}, {17, 130}, {15, 102}, {14, 178}, {11, 0}, {9, 12}, {8, 10}, {8, 7}, {9, 11}, {9, 10}, {10, 17}, {10, 11}, {10, 9}, {11, 13}, {11, 12}, {11, 10}, {11, 7}, {11, 5}, {11, 3}, {11, 1}, {8, 3} }; static const short tree20[] = { -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab20[] = { {1, 1}, {4, 5}, {6, 14}, {8, 44}, {9, 74}, {9, 63}, {10, 110}, {10, 93}, {11, 172}, {11, 149}, {11, 138}, {12, 242}, {12, 225}, {12, 195}, {13, 120}, {9, 17}, {3, 3}, {4, 4}, {6, 12}, {7, 20}, {8, 35}, {9, 62}, {9, 53}, {9, 47}, {10, 83}, {10, 75}, {10, 68}, {11, 119}, {12, 201}, {11, 107}, {12, 207}, {8, 9}, {6, 15}, {6, 13}, {7, 23}, {8, 38}, {9, 67}, {9, 58}, {10, 103}, {10, 90}, {11, 161}, {10, 72}, {11, 127}, {11, 117}, {11, 110}, {12, 209}, {12, 206}, {9, 16}, {8, 45}, {7, 21}, {8, 39}, {9, 69}, {9, 64}, {10, 114}, {10, 99}, {10, 87}, {11, 158}, {11, 140}, {12, 252}, {12, 212}, {12, 199}, {13, 131}, {13, 109}, {10, 26}, {9, 75}, {8, 36}, {9, 68}, {9, 65}, {10, 115}, {10, 101}, {11, 179}, {11, 164}, {11, 155}, {12, 8}, {12, 246}, {12, 226}, {13, 139}, {13, 126}, {13, 106}, {9, 9}, {9, 66}, {8, 30}, {9, 59}, {9, 56}, {10, 102}, {11, 185}, {11, 173}, {12, 9}, {11, 142}, {12, 253}, {12, 232}, {13, 144}, {13, 132}, {13, 122}, {14, 189}, {10, 16}, {10, 111}, {9, 54}, {9, 52}, {10, 100}, {11, 184}, {11, 178}, {11, 160}, {11, 133}, {12, 1}, {12, 244}, {12, 228}, {12, 217}, {13, 129}, {13, 110}, {14, 203}, {10, 10}, {10, 98}, {9, 48}, {10, 91}, {10, 88}, {11, 165}, {11, 157}, {11, 148}, {12, 5}, {12, 248}, {13, 151}, {13, 141}, {13, 116}, {13, 124}, {15, 121}, {15, 116}, {10, 8}, {10, 85}, {10, 84}, {10, 81}, {11, 159}, {11, 156}, {11, 143}, {12, 4}, {12, 249}, {13, 171}, {13, 145}, {13, 136}, {13, 127}, {14, 215}, {14, 201}, {14, 196}, {10, 7}, {11, 154}, {10, 76}, {10, 73}, {11, 141}, {11, 131}, {12, 0}, {12, 245}, {13, 170}, {13, 150}, {13, 138}, {13, 128}, {14, 223}, {13, 103}, {14, 198}, {13, 96}, {11, 11}, {11, 139}, {11, 129}, {10, 67}, {11, 125}, {12, 247}, {12, 233}, {12, 229}, {12, 219}, {13, 137}, {14, 231}, {14, 225}, {14, 208}, {15, 117}, {15, 114}, {14, 183}, {10, 4}, {12, 243}, {11, 120}, {11, 118}, {11, 115}, {12, 227}, {12, 223}, {13, 140}, {14, 234}, {14, 230}, {14, 224}, {14, 209}, {14, 200}, {14, 194}, {13, 223}, {14, 180}, {11, 6}, {12, 202}, {12, 224}, {12, 222}, {12, 218}, {12, 216}, {13, 133}, {13, 130}, {13, 125}, {13, 108}, {15, 120}, {14, 187}, {14, 195}, {14, 184}, {14, 181}, {16, 192}, {11, 4}, {14, 235}, {12, 211}, {12, 210}, {12, 208}, {13, 114}, {13, 123}, {14, 222}, {14, 211}, {14, 202}, {16, 199}, {15, 115}, {15, 109}, {15, 108}, {17, 131}, {15, 97}, {11, 2}, {13, 121}, {13, 113}, {11, 102}, {12, 187}, {14, 214}, {14, 210}, {13, 102}, {14, 199}, {14, 197}, {15, 98}, {16, 198}, {15, 103}, {17, 130}, {15, 102}, {14, 178}, {11, 0}, {9, 12}, {8, 10}, {8, 7}, {9, 11}, {9, 10}, {10, 17}, {10, 11}, {10, 9}, {11, 13}, {11, 12}, {11, 10}, {11, 7}, {11, 5}, {11, 3}, {11, 1}, {8, 3} }; static const short tree21[] = { -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab21[] = { {1, 1}, {4, 5}, {6, 14}, {8, 44}, {9, 74}, {9, 63}, {10, 110}, {10, 93}, {11, 172}, {11, 149}, {11, 138}, {12, 242}, {12, 225}, {12, 195}, {13, 120}, {9, 17}, {3, 3}, {4, 4}, {6, 12}, {7, 20}, {8, 35}, {9, 62}, {9, 53}, {9, 47}, {10, 83}, {10, 75}, {10, 68}, {11, 119}, {12, 201}, {11, 107}, {12, 207}, {8, 9}, {6, 15}, {6, 13}, {7, 23}, {8, 38}, {9, 67}, {9, 58}, {10, 103}, {10, 90}, {11, 161}, {10, 72}, {11, 127}, {11, 117}, {11, 110}, {12, 209}, {12, 206}, {9, 16}, {8, 45}, {7, 21}, {8, 39}, {9, 69}, {9, 64}, {10, 114}, {10, 99}, {10, 87}, {11, 158}, {11, 140}, {12, 252}, {12, 212}, {12, 199}, {13, 131}, {13, 109}, {10, 26}, {9, 75}, {8, 36}, {9, 68}, {9, 65}, {10, 115}, {10, 101}, {11, 179}, {11, 164}, {11, 155}, {12, 8}, {12, 246}, {12, 226}, {13, 139}, {13, 126}, {13, 106}, {9, 9}, {9, 66}, {8, 30}, {9, 59}, {9, 56}, {10, 102}, {11, 185}, {11, 173}, {12, 9}, {11, 142}, {12, 253}, {12, 232}, {13, 144}, {13, 132}, {13, 122}, {14, 189}, {10, 16}, {10, 111}, {9, 54}, {9, 52}, {10, 100}, {11, 184}, {11, 178}, {11, 160}, {11, 133}, {12, 1}, {12, 244}, {12, 228}, {12, 217}, {13, 129}, {13, 110}, {14, 203}, {10, 10}, {10, 98}, {9, 48}, {10, 91}, {10, 88}, {11, 165}, {11, 157}, {11, 148}, {12, 5}, {12, 248}, {13, 151}, {13, 141}, {13, 116}, {13, 124}, {15, 121}, {15, 116}, {10, 8}, {10, 85}, {10, 84}, {10, 81}, {11, 159}, {11, 156}, {11, 143}, {12, 4}, {12, 249}, {13, 171}, {13, 145}, {13, 136}, {13, 127}, {14, 215}, {14, 201}, {14, 196}, {10, 7}, {11, 154}, {10, 76}, {10, 73}, {11, 141}, {11, 131}, {12, 0}, {12, 245}, {13, 170}, {13, 150}, {13, 138}, {13, 128}, {14, 223}, {13, 103}, {14, 198}, {13, 96}, {11, 11}, {11, 139}, {11, 129}, {10, 67}, {11, 125}, {12, 247}, {12, 233}, {12, 229}, {12, 219}, {13, 137}, {14, 231}, {14, 225}, {14, 208}, {15, 117}, {15, 114}, {14, 183}, {10, 4}, {12, 243}, {11, 120}, {11, 118}, {11, 115}, {12, 227}, {12, 223}, {13, 140}, {14, 234}, {14, 230}, {14, 224}, {14, 209}, {14, 200}, {14, 194}, {13, 223}, {14, 180}, {11, 6}, {12, 202}, {12, 224}, {12, 222}, {12, 218}, {12, 216}, {13, 133}, {13, 130}, {13, 125}, {13, 108}, {15, 120}, {14, 187}, {14, 195}, {14, 184}, {14, 181}, {16, 192}, {11, 4}, {14, 235}, {12, 211}, {12, 210}, {12, 208}, {13, 114}, {13, 123}, {14, 222}, {14, 211}, {14, 202}, {16, 199}, {15, 115}, {15, 109}, {15, 108}, {17, 131}, {15, 97}, {11, 2}, {13, 121}, {13, 113}, {11, 102}, {12, 187}, {14, 214}, {14, 210}, {13, 102}, {14, 199}, {14, 197}, {15, 98}, {16, 198}, {15, 103}, {17, 130}, {15, 102}, {14, 178}, {11, 0}, {9, 12}, {8, 10}, {8, 7}, {9, 11}, {9, 10}, {10, 17}, {10, 11}, {10, 9}, {11, 13}, {11, 12}, {11, 10}, {11, 7}, {11, 5}, {11, 3}, {11, 1}, {8, 3} }; static const short tree22[] = { -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab22[] = { {1, 1}, {4, 5}, {6, 14}, {8, 44}, {9, 74}, {9, 63}, {10, 110}, {10, 93}, {11, 172}, {11, 149}, {11, 138}, {12, 242}, {12, 225}, {12, 195}, {13, 120}, {9, 17}, {3, 3}, {4, 4}, {6, 12}, {7, 20}, {8, 35}, {9, 62}, {9, 53}, {9, 47}, {10, 83}, {10, 75}, {10, 68}, {11, 119}, {12, 201}, {11, 107}, {12, 207}, {8, 9}, {6, 15}, {6, 13}, {7, 23}, {8, 38}, {9, 67}, {9, 58}, {10, 103}, {10, 90}, {11, 161}, {10, 72}, {11, 127}, {11, 117}, {11, 110}, {12, 209}, {12, 206}, {9, 16}, {8, 45}, {7, 21}, {8, 39}, {9, 69}, {9, 64}, {10, 114}, {10, 99}, {10, 87}, {11, 158}, {11, 140}, {12, 252}, {12, 212}, {12, 199}, {13, 131}, {13, 109}, {10, 26}, {9, 75}, {8, 36}, {9, 68}, {9, 65}, {10, 115}, {10, 101}, {11, 179}, {11, 164}, {11, 155}, {12, 8}, {12, 246}, {12, 226}, {13, 139}, {13, 126}, {13, 106}, {9, 9}, {9, 66}, {8, 30}, {9, 59}, {9, 56}, {10, 102}, {11, 185}, {11, 173}, {12, 9}, {11, 142}, {12, 253}, {12, 232}, {13, 144}, {13, 132}, {13, 122}, {14, 189}, {10, 16}, {10, 111}, {9, 54}, {9, 52}, {10, 100}, {11, 184}, {11, 178}, {11, 160}, {11, 133}, {12, 1}, {12, 244}, {12, 228}, {12, 217}, {13, 129}, {13, 110}, {14, 203}, {10, 10}, {10, 98}, {9, 48}, {10, 91}, {10, 88}, {11, 165}, {11, 157}, {11, 148}, {12, 5}, {12, 248}, {13, 151}, {13, 141}, {13, 116}, {13, 124}, {15, 121}, {15, 116}, {10, 8}, {10, 85}, {10, 84}, {10, 81}, {11, 159}, {11, 156}, {11, 143}, {12, 4}, {12, 249}, {13, 171}, {13, 145}, {13, 136}, {13, 127}, {14, 215}, {14, 201}, {14, 196}, {10, 7}, {11, 154}, {10, 76}, {10, 73}, {11, 141}, {11, 131}, {12, 0}, {12, 245}, {13, 170}, {13, 150}, {13, 138}, {13, 128}, {14, 223}, {13, 103}, {14, 198}, {13, 96}, {11, 11}, {11, 139}, {11, 129}, {10, 67}, {11, 125}, {12, 247}, {12, 233}, {12, 229}, {12, 219}, {13, 137}, {14, 231}, {14, 225}, {14, 208}, {15, 117}, {15, 114}, {14, 183}, {10, 4}, {12, 243}, {11, 120}, {11, 118}, {11, 115}, {12, 227}, {12, 223}, {13, 140}, {14, 234}, {14, 230}, {14, 224}, {14, 209}, {14, 200}, {14, 194}, {13, 223}, {14, 180}, {11, 6}, {12, 202}, {12, 224}, {12, 222}, {12, 218}, {12, 216}, {13, 133}, {13, 130}, {13, 125}, {13, 108}, {15, 120}, {14, 187}, {14, 195}, {14, 184}, {14, 181}, {16, 192}, {11, 4}, {14, 235}, {12, 211}, {12, 210}, {12, 208}, {13, 114}, {13, 123}, {14, 222}, {14, 211}, {14, 202}, {16, 199}, {15, 115}, {15, 109}, {15, 108}, {17, 131}, {15, 97}, {11, 2}, {13, 121}, {13, 113}, {11, 102}, {12, 187}, {14, 214}, {14, 210}, {13, 102}, {14, 199}, {14, 197}, {15, 98}, {16, 198}, {15, 103}, {17, 130}, {15, 102}, {14, 178}, {11, 0}, {9, 12}, {8, 10}, {8, 7}, {9, 11}, {9, 10}, {10, 17}, {10, 11}, {10, 9}, {11, 13}, {11, 12}, {11, 10}, {11, 7}, {11, 5}, {11, 3}, {11, 1}, {8, 3} }; static const short tree23[] = { -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; static const huffman_code_t tab23[] = { {1, 1}, {4, 5}, {6, 14}, {8, 44}, {9, 74}, {9, 63}, {10, 110}, {10, 93}, {11, 172}, {11, 149}, {11, 138}, {12, 242}, {12, 225}, {12, 195}, {13, 120}, {9, 17}, {3, 3}, {4, 4}, {6, 12}, {7, 20}, {8, 35}, {9, 62}, {9, 53}, {9, 47}, {10, 83}, {10, 75}, {10, 68}, {11, 119}, {12, 201}, {11, 107}, {12, 207}, {8, 9}, {6, 15}, {6, 13}, {7, 23}, {8, 38}, {9, 67}, {9, 58}, {10, 103}, {10, 90}, {11, 161}, {10, 72}, {11, 127}, {11, 117}, {11, 110}, {12, 209}, {12, 206}, {9, 16}, {8, 45}, {7, 21}, {8, 39}, {9, 69}, {9, 64}, {10, 114}, {10, 99}, {10, 87}, {11, 158}, {11, 140}, {12, 252}, {12, 212}, {12, 199}, {13, 131}, {13, 109}, {10, 26}, {9, 75}, {8, 36}, {9, 68}, {9, 65}, {10, 115}, {10, 101}, {11, 179}, {11, 164}, {11, 155}, {12, 8}, {12, 246}, {12, 226}, {13, 139}, {13, 126}, {13, 106}, {9, 9}, {9, 66}, {8, 30}, {9, 59}, {9, 56}, {10, 102}, {11, 185}, {11, 173}, {12, 9}, {11, 142}, {12, 253}, {12, 232}, {13, 144}, {13, 132}, {13, 122}, {14, 189}, {10, 16}, {10, 111}, {9, 54}, {9, 52}, {10, 100}, {11, 184}, {11, 178}, {11, 160}, {11, 133}, {12, 1}, {12, 244}, {12, 228}, {12, 217}, {13, 129}, {13, 110}, {14, 203}, {10, 10}, {10, 98}, {9, 48}, {10, 91}, {10, 88}, {11, 165}, {11, 157}, {11, 148}, {12, 5}, {12, 248}, {13, 151}, {13, 141}, {13, 116}, {13, 124}, {15, 121}, {15, 116}, {10, 8}, {10, 85}, {10, 84}, {10, 81}, {11, 159}, {11, 156}, {11, 143}, {12, 4}, {12, 249}, {13, 171}, {13, 145}, {13, 136}, {13, 127}, {14, 215}, {14, 201}, {14, 196}, {10, 7}, {11, 154}, {10, 76}, {10, 73}, {11, 141}, {11, 131}, {12, 0}, {12, 245}, {13, 170}, {13, 150}, {13, 138}, {13, 128}, {14, 223}, {13, 103}, {14, 198}, {13, 96}, {11, 11}, {11, 139}, {11, 129}, {10, 67}, {11, 125}, {12, 247}, {12, 233}, {12, 229}, {12, 219}, {13, 137}, {14, 231}, {14, 225}, {14, 208}, {15, 117}, {15, 114}, {14, 183}, {10, 4}, {12, 243}, {11, 120}, {11, 118}, {11, 115}, {12, 227}, {12, 223}, {13, 140}, {14, 234}, {14, 230}, {14, 224}, {14, 209}, {14, 200}, {14, 194}, {13, 223}, {14, 180}, {11, 6}, {12, 202}, {12, 224}, {12, 222}, {12, 218}, {12, 216}, {13, 133}, {13, 130}, {13, 125}, {13, 108}, {15, 120}, {14, 187}, {14, 195}, {14, 184}, {14, 181}, {16, 192}, {11, 4}, {14, 235}, {12, 211}, {12, 210}, {12, 208}, {13, 114}, {13, 123}, {14, 222}, {14, 211}, {14, 202}, {16, 199}, {15, 115}, {15, 109}, {15, 108}, {17, 131}, {15, 97}, {11, 2}, {13, 121}, {13, 113}, {11, 102}, {12, 187}, {14, 214}, {14, 210}, {13, 102}, {14, 199}, {14, 197}, {15, 98}, {16, 198}, {15, 103}, {17, 130}, {15, 102}, {14, 178}, {11, 0}, {9, 12}, {8, 10}, {8, 7}, {9, 11}, {9, 10}, {10, 17}, {10, 11}, {10, 9}, {11, 13}, {11, 12}, {11, 10}, {11, 7}, {11, 5}, {11, 3}, {11, 1}, {8, 3} }; static const short tree24[] = { -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab24[] = { {4, 15}, {4, 13}, {6, 46}, {7, 80}, {8, 146}, {9, 6}, {9, 248}, {10, 178}, {10, 170}, {11, 157}, {11, 141}, {11, 137}, {11, 109}, {11, 5}, {12, 8}, {9, 88}, {4, 14}, {4, 12}, {5, 21}, {6, 38}, {7, 71}, {8, 130}, {8, 122}, {9, 216}, {9, 209}, {9, 198}, {10, 71}, {10, 89}, {10, 63}, {10, 41}, {10, 23}, {8, 42}, {6, 47}, {5, 22}, {6, 41}, {7, 74}, {7, 68}, {8, 128}, {8, 120}, {9, 221}, {9, 207}, {9, 194}, {9, 182}, {10, 84}, {10, 59}, {10, 39}, {11, 29}, {7, 18}, {7, 81}, {6, 39}, {7, 75}, {7, 70}, {8, 134}, {8, 125}, {8, 116}, {9, 220}, {9, 204}, {9, 190}, {9, 178}, {10, 69}, {10, 55}, {10, 37}, {10, 15}, {7, 16}, {8, 147}, {7, 72}, {7, 69}, {8, 135}, {8, 127}, {8, 118}, {8, 112}, {9, 210}, {9, 200}, {9, 188}, {10, 96}, {10, 67}, {10, 50}, {10, 29}, {11, 28}, {7, 14}, {9, 7}, {7, 66}, {8, 129}, {8, 126}, {8, 119}, {8, 114}, {9, 214}, {9, 202}, {9, 192}, {9, 180}, {10, 85}, {10, 61}, {10, 45}, {10, 25}, {10, 6}, {7, 12}, {9, 249}, {8, 123}, {8, 121}, {8, 117}, {8, 113}, {9, 215}, {9, 206}, {9, 195}, {9, 185}, {10, 91}, {10, 74}, {10, 52}, {10, 35}, {10, 16}, {11, 8}, {7, 10}, {10, 179}, {8, 115}, {8, 111}, {8, 109}, {9, 211}, {9, 203}, {9, 196}, {9, 187}, {10, 97}, {10, 76}, {10, 57}, {10, 42}, {10, 27}, {11, 19}, {11, 125}, {8, 17}, {10, 171}, {9, 212}, {9, 208}, {9, 205}, {9, 201}, {9, 193}, {9, 186}, {9, 177}, {9, 169}, {10, 64}, {10, 47}, {10, 30}, {10, 12}, {11, 2}, {11, 121}, {8, 16}, {10, 79}, {9, 199}, {9, 197}, {9, 191}, {9, 189}, {9, 181}, {9, 174}, {10, 77}, {10, 65}, {10, 49}, {10, 33}, {10, 19}, {11, 9}, {11, 123}, {11, 115}, {8, 11}, {11, 156}, {9, 184}, {9, 183}, {9, 179}, {9, 175}, {10, 88}, {10, 75}, {10, 58}, {10, 48}, {10, 34}, {10, 21}, {11, 18}, {11, 127}, {11, 117}, {11, 110}, {8, 10}, {11, 140}, {10, 90}, {9, 171}, {9, 168}, {9, 164}, {10, 62}, {10, 53}, {10, 43}, {10, 31}, {10, 20}, {10, 7}, {11, 1}, {11, 119}, {11, 112}, {11, 106}, {8, 6}, {11, 136}, {10, 66}, {10, 60}, {10, 56}, {10, 51}, {10, 46}, {10, 36}, {10, 28}, {10, 13}, {10, 5}, {11, 0}, {11, 120}, {11, 114}, {11, 108}, {11, 103}, {8, 4}, {11, 108}, {10, 44}, {10, 40}, {10, 38}, {10, 32}, {10, 26}, {10, 17}, {10, 10}, {11, 3}, {11, 124}, {11, 118}, {11, 113}, {11, 109}, {11, 105}, {11, 101}, {8, 2}, {12, 9}, {10, 24}, {10, 22}, {10, 18}, {10, 11}, {10, 8}, {10, 3}, {11, 126}, {11, 122}, {11, 116}, {11, 111}, {11, 107}, {11, 104}, {11, 102}, {11, 100}, {8, 0}, {8, 43}, {7, 20}, {7, 19}, {7, 17}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 6}, {7, 4}, {8, 7}, {8, 5}, {8, 3}, {8, 1}, {4, 3} }; static const short tree25[] = { -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab25[] = { {4, 15}, {4, 13}, {6, 46}, {7, 80}, {8, 146}, {9, 6}, {9, 248}, {10, 178}, {10, 170}, {11, 157}, {11, 141}, {11, 137}, {11, 109}, {11, 5}, {12, 8}, {9, 88}, {4, 14}, {4, 12}, {5, 21}, {6, 38}, {7, 71}, {8, 130}, {8, 122}, {9, 216}, {9, 209}, {9, 198}, {10, 71}, {10, 89}, {10, 63}, {10, 41}, {10, 23}, {8, 42}, {6, 47}, {5, 22}, {6, 41}, {7, 74}, {7, 68}, {8, 128}, {8, 120}, {9, 221}, {9, 207}, {9, 194}, {9, 182}, {10, 84}, {10, 59}, {10, 39}, {11, 29}, {7, 18}, {7, 81}, {6, 39}, {7, 75}, {7, 70}, {8, 134}, {8, 125}, {8, 116}, {9, 220}, {9, 204}, {9, 190}, {9, 178}, {10, 69}, {10, 55}, {10, 37}, {10, 15}, {7, 16}, {8, 147}, {7, 72}, {7, 69}, {8, 135}, {8, 127}, {8, 118}, {8, 112}, {9, 210}, {9, 200}, {9, 188}, {10, 96}, {10, 67}, {10, 50}, {10, 29}, {11, 28}, {7, 14}, {9, 7}, {7, 66}, {8, 129}, {8, 126}, {8, 119}, {8, 114}, {9, 214}, {9, 202}, {9, 192}, {9, 180}, {10, 85}, {10, 61}, {10, 45}, {10, 25}, {10, 6}, {7, 12}, {9, 249}, {8, 123}, {8, 121}, {8, 117}, {8, 113}, {9, 215}, {9, 206}, {9, 195}, {9, 185}, {10, 91}, {10, 74}, {10, 52}, {10, 35}, {10, 16}, {11, 8}, {7, 10}, {10, 179}, {8, 115}, {8, 111}, {8, 109}, {9, 211}, {9, 203}, {9, 196}, {9, 187}, {10, 97}, {10, 76}, {10, 57}, {10, 42}, {10, 27}, {11, 19}, {11, 125}, {8, 17}, {10, 171}, {9, 212}, {9, 208}, {9, 205}, {9, 201}, {9, 193}, {9, 186}, {9, 177}, {9, 169}, {10, 64}, {10, 47}, {10, 30}, {10, 12}, {11, 2}, {11, 121}, {8, 16}, {10, 79}, {9, 199}, {9, 197}, {9, 191}, {9, 189}, {9, 181}, {9, 174}, {10, 77}, {10, 65}, {10, 49}, {10, 33}, {10, 19}, {11, 9}, {11, 123}, {11, 115}, {8, 11}, {11, 156}, {9, 184}, {9, 183}, {9, 179}, {9, 175}, {10, 88}, {10, 75}, {10, 58}, {10, 48}, {10, 34}, {10, 21}, {11, 18}, {11, 127}, {11, 117}, {11, 110}, {8, 10}, {11, 140}, {10, 90}, {9, 171}, {9, 168}, {9, 164}, {10, 62}, {10, 53}, {10, 43}, {10, 31}, {10, 20}, {10, 7}, {11, 1}, {11, 119}, {11, 112}, {11, 106}, {8, 6}, {11, 136}, {10, 66}, {10, 60}, {10, 56}, {10, 51}, {10, 46}, {10, 36}, {10, 28}, {10, 13}, {10, 5}, {11, 0}, {11, 120}, {11, 114}, {11, 108}, {11, 103}, {8, 4}, {11, 108}, {10, 44}, {10, 40}, {10, 38}, {10, 32}, {10, 26}, {10, 17}, {10, 10}, {11, 3}, {11, 124}, {11, 118}, {11, 113}, {11, 109}, {11, 105}, {11, 101}, {8, 2}, {12, 9}, {10, 24}, {10, 22}, {10, 18}, {10, 11}, {10, 8}, {10, 3}, {11, 126}, {11, 122}, {11, 116}, {11, 111}, {11, 107}, {11, 104}, {11, 102}, {11, 100}, {8, 0}, {8, 43}, {7, 20}, {7, 19}, {7, 17}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 6}, {7, 4}, {8, 7}, {8, 5}, {8, 3}, {8, 1}, {4, 3} }; static const short tree26[] = { -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab26[] = { {4, 15}, {4, 13}, {6, 46}, {7, 80}, {8, 146}, {9, 6}, {9, 248}, {10, 178}, {10, 170}, {11, 157}, {11, 141}, {11, 137}, {11, 109}, {11, 5}, {12, 8}, {9, 88}, {4, 14}, {4, 12}, {5, 21}, {6, 38}, {7, 71}, {8, 130}, {8, 122}, {9, 216}, {9, 209}, {9, 198}, {10, 71}, {10, 89}, {10, 63}, {10, 41}, {10, 23}, {8, 42}, {6, 47}, {5, 22}, {6, 41}, {7, 74}, {7, 68}, {8, 128}, {8, 120}, {9, 221}, {9, 207}, {9, 194}, {9, 182}, {10, 84}, {10, 59}, {10, 39}, {11, 29}, {7, 18}, {7, 81}, {6, 39}, {7, 75}, {7, 70}, {8, 134}, {8, 125}, {8, 116}, {9, 220}, {9, 204}, {9, 190}, {9, 178}, {10, 69}, {10, 55}, {10, 37}, {10, 15}, {7, 16}, {8, 147}, {7, 72}, {7, 69}, {8, 135}, {8, 127}, {8, 118}, {8, 112}, {9, 210}, {9, 200}, {9, 188}, {10, 96}, {10, 67}, {10, 50}, {10, 29}, {11, 28}, {7, 14}, {9, 7}, {7, 66}, {8, 129}, {8, 126}, {8, 119}, {8, 114}, {9, 214}, {9, 202}, {9, 192}, {9, 180}, {10, 85}, {10, 61}, {10, 45}, {10, 25}, {10, 6}, {7, 12}, {9, 249}, {8, 123}, {8, 121}, {8, 117}, {8, 113}, {9, 215}, {9, 206}, {9, 195}, {9, 185}, {10, 91}, {10, 74}, {10, 52}, {10, 35}, {10, 16}, {11, 8}, {7, 10}, {10, 179}, {8, 115}, {8, 111}, {8, 109}, {9, 211}, {9, 203}, {9, 196}, {9, 187}, {10, 97}, {10, 76}, {10, 57}, {10, 42}, {10, 27}, {11, 19}, {11, 125}, {8, 17}, {10, 171}, {9, 212}, {9, 208}, {9, 205}, {9, 201}, {9, 193}, {9, 186}, {9, 177}, {9, 169}, {10, 64}, {10, 47}, {10, 30}, {10, 12}, {11, 2}, {11, 121}, {8, 16}, {10, 79}, {9, 199}, {9, 197}, {9, 191}, {9, 189}, {9, 181}, {9, 174}, {10, 77}, {10, 65}, {10, 49}, {10, 33}, {10, 19}, {11, 9}, {11, 123}, {11, 115}, {8, 11}, {11, 156}, {9, 184}, {9, 183}, {9, 179}, {9, 175}, {10, 88}, {10, 75}, {10, 58}, {10, 48}, {10, 34}, {10, 21}, {11, 18}, {11, 127}, {11, 117}, {11, 110}, {8, 10}, {11, 140}, {10, 90}, {9, 171}, {9, 168}, {9, 164}, {10, 62}, {10, 53}, {10, 43}, {10, 31}, {10, 20}, {10, 7}, {11, 1}, {11, 119}, {11, 112}, {11, 106}, {8, 6}, {11, 136}, {10, 66}, {10, 60}, {10, 56}, {10, 51}, {10, 46}, {10, 36}, {10, 28}, {10, 13}, {10, 5}, {11, 0}, {11, 120}, {11, 114}, {11, 108}, {11, 103}, {8, 4}, {11, 108}, {10, 44}, {10, 40}, {10, 38}, {10, 32}, {10, 26}, {10, 17}, {10, 10}, {11, 3}, {11, 124}, {11, 118}, {11, 113}, {11, 109}, {11, 105}, {11, 101}, {8, 2}, {12, 9}, {10, 24}, {10, 22}, {10, 18}, {10, 11}, {10, 8}, {10, 3}, {11, 126}, {11, 122}, {11, 116}, {11, 111}, {11, 107}, {11, 104}, {11, 102}, {11, 100}, {8, 0}, {8, 43}, {7, 20}, {7, 19}, {7, 17}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 6}, {7, 4}, {8, 7}, {8, 5}, {8, 3}, {8, 1}, {4, 3} }; static const short tree27[] = { -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab27[] = { {4, 15}, {4, 13}, {6, 46}, {7, 80}, {8, 146}, {9, 6}, {9, 248}, {10, 178}, {10, 170}, {11, 157}, {11, 141}, {11, 137}, {11, 109}, {11, 5}, {12, 8}, {9, 88}, {4, 14}, {4, 12}, {5, 21}, {6, 38}, {7, 71}, {8, 130}, {8, 122}, {9, 216}, {9, 209}, {9, 198}, {10, 71}, {10, 89}, {10, 63}, {10, 41}, {10, 23}, {8, 42}, {6, 47}, {5, 22}, {6, 41}, {7, 74}, {7, 68}, {8, 128}, {8, 120}, {9, 221}, {9, 207}, {9, 194}, {9, 182}, {10, 84}, {10, 59}, {10, 39}, {11, 29}, {7, 18}, {7, 81}, {6, 39}, {7, 75}, {7, 70}, {8, 134}, {8, 125}, {8, 116}, {9, 220}, {9, 204}, {9, 190}, {9, 178}, {10, 69}, {10, 55}, {10, 37}, {10, 15}, {7, 16}, {8, 147}, {7, 72}, {7, 69}, {8, 135}, {8, 127}, {8, 118}, {8, 112}, {9, 210}, {9, 200}, {9, 188}, {10, 96}, {10, 67}, {10, 50}, {10, 29}, {11, 28}, {7, 14}, {9, 7}, {7, 66}, {8, 129}, {8, 126}, {8, 119}, {8, 114}, {9, 214}, {9, 202}, {9, 192}, {9, 180}, {10, 85}, {10, 61}, {10, 45}, {10, 25}, {10, 6}, {7, 12}, {9, 249}, {8, 123}, {8, 121}, {8, 117}, {8, 113}, {9, 215}, {9, 206}, {9, 195}, {9, 185}, {10, 91}, {10, 74}, {10, 52}, {10, 35}, {10, 16}, {11, 8}, {7, 10}, {10, 179}, {8, 115}, {8, 111}, {8, 109}, {9, 211}, {9, 203}, {9, 196}, {9, 187}, {10, 97}, {10, 76}, {10, 57}, {10, 42}, {10, 27}, {11, 19}, {11, 125}, {8, 17}, {10, 171}, {9, 212}, {9, 208}, {9, 205}, {9, 201}, {9, 193}, {9, 186}, {9, 177}, {9, 169}, {10, 64}, {10, 47}, {10, 30}, {10, 12}, {11, 2}, {11, 121}, {8, 16}, {10, 79}, {9, 199}, {9, 197}, {9, 191}, {9, 189}, {9, 181}, {9, 174}, {10, 77}, {10, 65}, {10, 49}, {10, 33}, {10, 19}, {11, 9}, {11, 123}, {11, 115}, {8, 11}, {11, 156}, {9, 184}, {9, 183}, {9, 179}, {9, 175}, {10, 88}, {10, 75}, {10, 58}, {10, 48}, {10, 34}, {10, 21}, {11, 18}, {11, 127}, {11, 117}, {11, 110}, {8, 10}, {11, 140}, {10, 90}, {9, 171}, {9, 168}, {9, 164}, {10, 62}, {10, 53}, {10, 43}, {10, 31}, {10, 20}, {10, 7}, {11, 1}, {11, 119}, {11, 112}, {11, 106}, {8, 6}, {11, 136}, {10, 66}, {10, 60}, {10, 56}, {10, 51}, {10, 46}, {10, 36}, {10, 28}, {10, 13}, {10, 5}, {11, 0}, {11, 120}, {11, 114}, {11, 108}, {11, 103}, {8, 4}, {11, 108}, {10, 44}, {10, 40}, {10, 38}, {10, 32}, {10, 26}, {10, 17}, {10, 10}, {11, 3}, {11, 124}, {11, 118}, {11, 113}, {11, 109}, {11, 105}, {11, 101}, {8, 2}, {12, 9}, {10, 24}, {10, 22}, {10, 18}, {10, 11}, {10, 8}, {10, 3}, {11, 126}, {11, 122}, {11, 116}, {11, 111}, {11, 107}, {11, 104}, {11, 102}, {11, 100}, {8, 0}, {8, 43}, {7, 20}, {7, 19}, {7, 17}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 6}, {7, 4}, {8, 7}, {8, 5}, {8, 3}, {8, 1}, {4, 3} }; static const short tree28[] = { -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab28[] = { {4, 15}, {4, 13}, {6, 46}, {7, 80}, {8, 146}, {9, 6}, {9, 248}, {10, 178}, {10, 170}, {11, 157}, {11, 141}, {11, 137}, {11, 109}, {11, 5}, {12, 8}, {9, 88}, {4, 14}, {4, 12}, {5, 21}, {6, 38}, {7, 71}, {8, 130}, {8, 122}, {9, 216}, {9, 209}, {9, 198}, {10, 71}, {10, 89}, {10, 63}, {10, 41}, {10, 23}, {8, 42}, {6, 47}, {5, 22}, {6, 41}, {7, 74}, {7, 68}, {8, 128}, {8, 120}, {9, 221}, {9, 207}, {9, 194}, {9, 182}, {10, 84}, {10, 59}, {10, 39}, {11, 29}, {7, 18}, {7, 81}, {6, 39}, {7, 75}, {7, 70}, {8, 134}, {8, 125}, {8, 116}, {9, 220}, {9, 204}, {9, 190}, {9, 178}, {10, 69}, {10, 55}, {10, 37}, {10, 15}, {7, 16}, {8, 147}, {7, 72}, {7, 69}, {8, 135}, {8, 127}, {8, 118}, {8, 112}, {9, 210}, {9, 200}, {9, 188}, {10, 96}, {10, 67}, {10, 50}, {10, 29}, {11, 28}, {7, 14}, {9, 7}, {7, 66}, {8, 129}, {8, 126}, {8, 119}, {8, 114}, {9, 214}, {9, 202}, {9, 192}, {9, 180}, {10, 85}, {10, 61}, {10, 45}, {10, 25}, {10, 6}, {7, 12}, {9, 249}, {8, 123}, {8, 121}, {8, 117}, {8, 113}, {9, 215}, {9, 206}, {9, 195}, {9, 185}, {10, 91}, {10, 74}, {10, 52}, {10, 35}, {10, 16}, {11, 8}, {7, 10}, {10, 179}, {8, 115}, {8, 111}, {8, 109}, {9, 211}, {9, 203}, {9, 196}, {9, 187}, {10, 97}, {10, 76}, {10, 57}, {10, 42}, {10, 27}, {11, 19}, {11, 125}, {8, 17}, {10, 171}, {9, 212}, {9, 208}, {9, 205}, {9, 201}, {9, 193}, {9, 186}, {9, 177}, {9, 169}, {10, 64}, {10, 47}, {10, 30}, {10, 12}, {11, 2}, {11, 121}, {8, 16}, {10, 79}, {9, 199}, {9, 197}, {9, 191}, {9, 189}, {9, 181}, {9, 174}, {10, 77}, {10, 65}, {10, 49}, {10, 33}, {10, 19}, {11, 9}, {11, 123}, {11, 115}, {8, 11}, {11, 156}, {9, 184}, {9, 183}, {9, 179}, {9, 175}, {10, 88}, {10, 75}, {10, 58}, {10, 48}, {10, 34}, {10, 21}, {11, 18}, {11, 127}, {11, 117}, {11, 110}, {8, 10}, {11, 140}, {10, 90}, {9, 171}, {9, 168}, {9, 164}, {10, 62}, {10, 53}, {10, 43}, {10, 31}, {10, 20}, {10, 7}, {11, 1}, {11, 119}, {11, 112}, {11, 106}, {8, 6}, {11, 136}, {10, 66}, {10, 60}, {10, 56}, {10, 51}, {10, 46}, {10, 36}, {10, 28}, {10, 13}, {10, 5}, {11, 0}, {11, 120}, {11, 114}, {11, 108}, {11, 103}, {8, 4}, {11, 108}, {10, 44}, {10, 40}, {10, 38}, {10, 32}, {10, 26}, {10, 17}, {10, 10}, {11, 3}, {11, 124}, {11, 118}, {11, 113}, {11, 109}, {11, 105}, {11, 101}, {8, 2}, {12, 9}, {10, 24}, {10, 22}, {10, 18}, {10, 11}, {10, 8}, {10, 3}, {11, 126}, {11, 122}, {11, 116}, {11, 111}, {11, 107}, {11, 104}, {11, 102}, {11, 100}, {8, 0}, {8, 43}, {7, 20}, {7, 19}, {7, 17}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 6}, {7, 4}, {8, 7}, {8, 5}, {8, 3}, {8, 1}, {4, 3} }; static const short tree29[] = { -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab29[] = { {4, 15}, {4, 13}, {6, 46}, {7, 80}, {8, 146}, {9, 6}, {9, 248}, {10, 178}, {10, 170}, {11, 157}, {11, 141}, {11, 137}, {11, 109}, {11, 5}, {12, 8}, {9, 88}, {4, 14}, {4, 12}, {5, 21}, {6, 38}, {7, 71}, {8, 130}, {8, 122}, {9, 216}, {9, 209}, {9, 198}, {10, 71}, {10, 89}, {10, 63}, {10, 41}, {10, 23}, {8, 42}, {6, 47}, {5, 22}, {6, 41}, {7, 74}, {7, 68}, {8, 128}, {8, 120}, {9, 221}, {9, 207}, {9, 194}, {9, 182}, {10, 84}, {10, 59}, {10, 39}, {11, 29}, {7, 18}, {7, 81}, {6, 39}, {7, 75}, {7, 70}, {8, 134}, {8, 125}, {8, 116}, {9, 220}, {9, 204}, {9, 190}, {9, 178}, {10, 69}, {10, 55}, {10, 37}, {10, 15}, {7, 16}, {8, 147}, {7, 72}, {7, 69}, {8, 135}, {8, 127}, {8, 118}, {8, 112}, {9, 210}, {9, 200}, {9, 188}, {10, 96}, {10, 67}, {10, 50}, {10, 29}, {11, 28}, {7, 14}, {9, 7}, {7, 66}, {8, 129}, {8, 126}, {8, 119}, {8, 114}, {9, 214}, {9, 202}, {9, 192}, {9, 180}, {10, 85}, {10, 61}, {10, 45}, {10, 25}, {10, 6}, {7, 12}, {9, 249}, {8, 123}, {8, 121}, {8, 117}, {8, 113}, {9, 215}, {9, 206}, {9, 195}, {9, 185}, {10, 91}, {10, 74}, {10, 52}, {10, 35}, {10, 16}, {11, 8}, {7, 10}, {10, 179}, {8, 115}, {8, 111}, {8, 109}, {9, 211}, {9, 203}, {9, 196}, {9, 187}, {10, 97}, {10, 76}, {10, 57}, {10, 42}, {10, 27}, {11, 19}, {11, 125}, {8, 17}, {10, 171}, {9, 212}, {9, 208}, {9, 205}, {9, 201}, {9, 193}, {9, 186}, {9, 177}, {9, 169}, {10, 64}, {10, 47}, {10, 30}, {10, 12}, {11, 2}, {11, 121}, {8, 16}, {10, 79}, {9, 199}, {9, 197}, {9, 191}, {9, 189}, {9, 181}, {9, 174}, {10, 77}, {10, 65}, {10, 49}, {10, 33}, {10, 19}, {11, 9}, {11, 123}, {11, 115}, {8, 11}, {11, 156}, {9, 184}, {9, 183}, {9, 179}, {9, 175}, {10, 88}, {10, 75}, {10, 58}, {10, 48}, {10, 34}, {10, 21}, {11, 18}, {11, 127}, {11, 117}, {11, 110}, {8, 10}, {11, 140}, {10, 90}, {9, 171}, {9, 168}, {9, 164}, {10, 62}, {10, 53}, {10, 43}, {10, 31}, {10, 20}, {10, 7}, {11, 1}, {11, 119}, {11, 112}, {11, 106}, {8, 6}, {11, 136}, {10, 66}, {10, 60}, {10, 56}, {10, 51}, {10, 46}, {10, 36}, {10, 28}, {10, 13}, {10, 5}, {11, 0}, {11, 120}, {11, 114}, {11, 108}, {11, 103}, {8, 4}, {11, 108}, {10, 44}, {10, 40}, {10, 38}, {10, 32}, {10, 26}, {10, 17}, {10, 10}, {11, 3}, {11, 124}, {11, 118}, {11, 113}, {11, 109}, {11, 105}, {11, 101}, {8, 2}, {12, 9}, {10, 24}, {10, 22}, {10, 18}, {10, 11}, {10, 8}, {10, 3}, {11, 126}, {11, 122}, {11, 116}, {11, 111}, {11, 107}, {11, 104}, {11, 102}, {11, 100}, {8, 0}, {8, 43}, {7, 20}, {7, 19}, {7, 17}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 6}, {7, 4}, {8, 7}, {8, 5}, {8, 3}, {8, 1}, {4, 3} }; static const short tree30[] = { -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab30[] = { {4, 15}, {4, 13}, {6, 46}, {7, 80}, {8, 146}, {9, 6}, {9, 248}, {10, 178}, {10, 170}, {11, 157}, {11, 141}, {11, 137}, {11, 109}, {11, 5}, {12, 8}, {9, 88}, {4, 14}, {4, 12}, {5, 21}, {6, 38}, {7, 71}, {8, 130}, {8, 122}, {9, 216}, {9, 209}, {9, 198}, {10, 71}, {10, 89}, {10, 63}, {10, 41}, {10, 23}, {8, 42}, {6, 47}, {5, 22}, {6, 41}, {7, 74}, {7, 68}, {8, 128}, {8, 120}, {9, 221}, {9, 207}, {9, 194}, {9, 182}, {10, 84}, {10, 59}, {10, 39}, {11, 29}, {7, 18}, {7, 81}, {6, 39}, {7, 75}, {7, 70}, {8, 134}, {8, 125}, {8, 116}, {9, 220}, {9, 204}, {9, 190}, {9, 178}, {10, 69}, {10, 55}, {10, 37}, {10, 15}, {7, 16}, {8, 147}, {7, 72}, {7, 69}, {8, 135}, {8, 127}, {8, 118}, {8, 112}, {9, 210}, {9, 200}, {9, 188}, {10, 96}, {10, 67}, {10, 50}, {10, 29}, {11, 28}, {7, 14}, {9, 7}, {7, 66}, {8, 129}, {8, 126}, {8, 119}, {8, 114}, {9, 214}, {9, 202}, {9, 192}, {9, 180}, {10, 85}, {10, 61}, {10, 45}, {10, 25}, {10, 6}, {7, 12}, {9, 249}, {8, 123}, {8, 121}, {8, 117}, {8, 113}, {9, 215}, {9, 206}, {9, 195}, {9, 185}, {10, 91}, {10, 74}, {10, 52}, {10, 35}, {10, 16}, {11, 8}, {7, 10}, {10, 179}, {8, 115}, {8, 111}, {8, 109}, {9, 211}, {9, 203}, {9, 196}, {9, 187}, {10, 97}, {10, 76}, {10, 57}, {10, 42}, {10, 27}, {11, 19}, {11, 125}, {8, 17}, {10, 171}, {9, 212}, {9, 208}, {9, 205}, {9, 201}, {9, 193}, {9, 186}, {9, 177}, {9, 169}, {10, 64}, {10, 47}, {10, 30}, {10, 12}, {11, 2}, {11, 121}, {8, 16}, {10, 79}, {9, 199}, {9, 197}, {9, 191}, {9, 189}, {9, 181}, {9, 174}, {10, 77}, {10, 65}, {10, 49}, {10, 33}, {10, 19}, {11, 9}, {11, 123}, {11, 115}, {8, 11}, {11, 156}, {9, 184}, {9, 183}, {9, 179}, {9, 175}, {10, 88}, {10, 75}, {10, 58}, {10, 48}, {10, 34}, {10, 21}, {11, 18}, {11, 127}, {11, 117}, {11, 110}, {8, 10}, {11, 140}, {10, 90}, {9, 171}, {9, 168}, {9, 164}, {10, 62}, {10, 53}, {10, 43}, {10, 31}, {10, 20}, {10, 7}, {11, 1}, {11, 119}, {11, 112}, {11, 106}, {8, 6}, {11, 136}, {10, 66}, {10, 60}, {10, 56}, {10, 51}, {10, 46}, {10, 36}, {10, 28}, {10, 13}, {10, 5}, {11, 0}, {11, 120}, {11, 114}, {11, 108}, {11, 103}, {8, 4}, {11, 108}, {10, 44}, {10, 40}, {10, 38}, {10, 32}, {10, 26}, {10, 17}, {10, 10}, {11, 3}, {11, 124}, {11, 118}, {11, 113}, {11, 109}, {11, 105}, {11, 101}, {8, 2}, {12, 9}, {10, 24}, {10, 22}, {10, 18}, {10, 11}, {10, 8}, {10, 3}, {11, 126}, {11, 122}, {11, 116}, {11, 111}, {11, 107}, {11, 104}, {11, 102}, {11, 100}, {8, 0}, {8, 43}, {7, 20}, {7, 19}, {7, 17}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 6}, {7, 4}, {8, 7}, {8, 5}, {8, 3}, {8, 1}, {4, 3} }; static const short tree31[] = { -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; static const huffman_code_t tab31[] = { {4, 15}, {4, 13}, {6, 46}, {7, 80}, {8, 146}, {9, 6}, {9, 248}, {10, 178}, {10, 170}, {11, 157}, {11, 141}, {11, 137}, {11, 109}, {11, 5}, {12, 8}, {9, 88}, {4, 14}, {4, 12}, {5, 21}, {6, 38}, {7, 71}, {8, 130}, {8, 122}, {9, 216}, {9, 209}, {9, 198}, {10, 71}, {10, 89}, {10, 63}, {10, 41}, {10, 23}, {8, 42}, {6, 47}, {5, 22}, {6, 41}, {7, 74}, {7, 68}, {8, 128}, {8, 120}, {9, 221}, {9, 207}, {9, 194}, {9, 182}, {10, 84}, {10, 59}, {10, 39}, {11, 29}, {7, 18}, {7, 81}, {6, 39}, {7, 75}, {7, 70}, {8, 134}, {8, 125}, {8, 116}, {9, 220}, {9, 204}, {9, 190}, {9, 178}, {10, 69}, {10, 55}, {10, 37}, {10, 15}, {7, 16}, {8, 147}, {7, 72}, {7, 69}, {8, 135}, {8, 127}, {8, 118}, {8, 112}, {9, 210}, {9, 200}, {9, 188}, {10, 96}, {10, 67}, {10, 50}, {10, 29}, {11, 28}, {7, 14}, {9, 7}, {7, 66}, {8, 129}, {8, 126}, {8, 119}, {8, 114}, {9, 214}, {9, 202}, {9, 192}, {9, 180}, {10, 85}, {10, 61}, {10, 45}, {10, 25}, {10, 6}, {7, 12}, {9, 249}, {8, 123}, {8, 121}, {8, 117}, {8, 113}, {9, 215}, {9, 206}, {9, 195}, {9, 185}, {10, 91}, {10, 74}, {10, 52}, {10, 35}, {10, 16}, {11, 8}, {7, 10}, {10, 179}, {8, 115}, {8, 111}, {8, 109}, {9, 211}, {9, 203}, {9, 196}, {9, 187}, {10, 97}, {10, 76}, {10, 57}, {10, 42}, {10, 27}, {11, 19}, {11, 125}, {8, 17}, {10, 171}, {9, 212}, {9, 208}, {9, 205}, {9, 201}, {9, 193}, {9, 186}, {9, 177}, {9, 169}, {10, 64}, {10, 47}, {10, 30}, {10, 12}, {11, 2}, {11, 121}, {8, 16}, {10, 79}, {9, 199}, {9, 197}, {9, 191}, {9, 189}, {9, 181}, {9, 174}, {10, 77}, {10, 65}, {10, 49}, {10, 33}, {10, 19}, {11, 9}, {11, 123}, {11, 115}, {8, 11}, {11, 156}, {9, 184}, {9, 183}, {9, 179}, {9, 175}, {10, 88}, {10, 75}, {10, 58}, {10, 48}, {10, 34}, {10, 21}, {11, 18}, {11, 127}, {11, 117}, {11, 110}, {8, 10}, {11, 140}, {10, 90}, {9, 171}, {9, 168}, {9, 164}, {10, 62}, {10, 53}, {10, 43}, {10, 31}, {10, 20}, {10, 7}, {11, 1}, {11, 119}, {11, 112}, {11, 106}, {8, 6}, {11, 136}, {10, 66}, {10, 60}, {10, 56}, {10, 51}, {10, 46}, {10, 36}, {10, 28}, {10, 13}, {10, 5}, {11, 0}, {11, 120}, {11, 114}, {11, 108}, {11, 103}, {8, 4}, {11, 108}, {10, 44}, {10, 40}, {10, 38}, {10, 32}, {10, 26}, {10, 17}, {10, 10}, {11, 3}, {11, 124}, {11, 118}, {11, 113}, {11, 109}, {11, 105}, {11, 101}, {8, 2}, {12, 9}, {10, 24}, {10, 22}, {10, 18}, {10, 11}, {10, 8}, {10, 3}, {11, 126}, {11, 122}, {11, 116}, {11, 111}, {11, 107}, {11, 104}, {11, 102}, {11, 100}, {8, 0}, {8, 43}, {7, 20}, {7, 19}, {7, 17}, {7, 15}, {7, 13}, {7, 11}, {7, 9}, {7, 7}, {7, 6}, {7, 4}, {8, 7}, {8, 5}, {8, 3}, {8, 1}, {4, 3} }; static const short tree32[] = { 0 }; static const huffman_code_t tab32[] = { {0, 0} }; static const short tree33[] = { 0 }; static huffman_code_t tab33[] = { {0, 0} }; static const huffman_tbl_t huffman_tables[] = { {tree0, tab0}, {tree1, tab1}, {tree2, tab2}, {tree3, tab3}, {tree4, tab4}, {tree5, tab5}, {tree6, tab6}, {tree7, tab7}, {tree8, tab8}, {tree9, tab9}, {tree10, tab10}, {tree11, tab11}, {tree12, tab12}, {tree13, tab13}, {tree14, tab14}, {tree15, tab15}, {tree16, tab16}, {tree17, tab17}, {tree18, tab18}, {tree19, tab19}, {tree20, tab20}, {tree21, tab21}, {tree22, tab22}, {tree23, tab23}, {tree24, tab24}, {tree25, tab25}, {tree26, tab26}, {tree27, tab27}, {tree28, tab28}, {tree29, tab29}, {tree30, tab30}, {tree31, tab31}, {tree32, tab32}, {tree33, tab33} }; int huffman_decode(bv_t * bv, int table) { const short *tree = huffman_tables[table].tree; int i; while ((i = *tree++) < 0) { unsigned long b; b = bv_get_bits(bv, 1); if (b == 1) tree -= i; } return i; } void huffman_dec(bv_t *bv, int table, int &x, int &y) { const huffman_tbl_t *tbl = huffman_tables + table; /* do the actual huffman decoding */ int xy = huffman_decode(bv, table); /* get x and y values */ *x = xy >> 4; *y = xy & 0xF; /* escaped value */ if (x == 15) *x += bv_get_bits(bv, tbl->linbits); /* get x sign */ if (x) { if (bv_get_bits(bv, 1)) *x = - *x; } if (y == 15) *y += bv_get_bits(bv, tbl->linbits); if (y) { if (bv_get_bits(bv, 1)) *y = - *y; } } void huffman_encode(bv_t *bv, int table, int value) { const huffman_code_t *code = huffman_tables[table].tab; bv_put_bits(bv, code[value].code, code[value].hlen); } void huffman_enc(bv_t *bv, int table, int x, int y) { const huffman_tbl_t *tbl = huffman_tables + table; int ax = abs(x); int ay = abs(y); int extx = 0, exty = 0; int xbits = 0, ybits = 0; if (ax) { if (ax < 0) extx = 1; xbits++; } if (ay) { if (ay < 0) exty = 1; ybits++; } if (table > 15) { if (ax > 14) { ax = 15; extx |= (ax - 15) << 1; xbits += tbl->linbits; assert(((ax - 15) < ((1 << tbl->linbits) - 1)) || "extension field for x is too big"); } if (ay > 14) { ay = 15; exty |= (ay - 15) << 1; ybits += tbl->linbits; assert(((ay - 15) < ((1 << tbl->linbits) - 1)) || "extension field for x is too big"); } } unsigned short value = ((ax & ((1 << tbl->xlen) - 1)) << tbl->xlen) | (ay & ((1 << tbl->ylen) - 1)); bv_put_bits(bv, tbl->tab[value].code, tbl->tab[value].hlen); bv_put_bits(bv, extx, xbits); bv_put_bits(bv, exty, ybits); } poc-0.4.2/signal.c0000664000175000001440000000110010210123147014340 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include "signal.h" /*M \emph{Set a new handler for a signal.} Returns the old handler on success, \verb|SIG_ERR| on error. Uses the new \verb|sigaction| API. **/ sig_handler_t *sig_set_handler(int signo, sig_handler_t *handler) { struct sigaction act, old_act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(signo, &act, &old_act) < 0) { perror("sigaction"); return SIG_ERR; } return old_act.sa_handler; } /*C **/ poc-0.4.2/file.c0000664000175000001440000000431510214014115014013 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #include "conf.h" #include #include #include #include #include #include #include #include #include #include "file.h" #include "misc.h" /*M \emph{Read and retry on interrupted system calls.} **/ int file_read(file_t *file, unsigned char *buf, size_t size) { assert(file != NULL); assert(buf != NULL); assert(size > 0); return unix_read(file->fd, buf, size); } /*M \emph{Seek forward in the file.} **/ int file_seek_fwd(file_t *file, size_t size) { if (lseek(file->fd, size, SEEK_CUR) < 0) return 0; else return 1; } /*M \emph{Open a file.} Return 0 on error, 1 on success. To read from STDIN, call with "-" as filename. **/ int file_open_read(file_t *file, char *filename) { assert(file != NULL); assert(filename != NULL); if (strcmp(filename, "-") == 0) { /* read from stdin */ file->fd = STDIN_FILENO; file->size = 0; } else { file->fd = open(filename, O_RDONLY); if (file->fd < 0) { perror("open"); return 0; } struct stat sb; if (stat(filename, &sb) < 0) { perror("stat"); return 0; } file->size = (unsigned long)sb.st_size; } file->offset = 0; return 1; } /*M \emph{Write a buffer to filedescriptor fd.} **/ int file_write(file_t *file, unsigned char *buf, size_t size) { assert(file != NULL); assert(buf != NULL); return unix_write(file->fd, buf, size); } /*M \emph{Open a file for writing.} **/ int file_open_write(file_t *file, char *filename) { assert(file != NULL); assert(filename != NULL); if (!strcmp(filename, "-")) /* write to stdout */ file->fd = STDOUT_FILENO; else { file->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IROTH); if (file->fd < 0) { perror("open"); return 0; } } file->offset = 0; return 1; } /*M \emph{Close a file.} Return 0 on error and 1 on success. **/ int file_close(file_t *file) { assert(file != NULL); if (file->fd != STDIN_FILENO) { if (close(file->fd) < 0) { perror("close"); return 0; } } return 1; } /*C **/ poc-0.4.2/signal.h0000664000175000001440000000042610210123147014357 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef SIGNAL_H__ #define SIGNAL_H__ #include /*M \emph{Function type for signal handlers.} **/ typedef void sig_handler_t(int); sig_handler_t *sig_set_handler(int signo, sig_handler_t *handler); #endif /* SIGNAL_H__ **/ /*C **/ poc-0.4.2/ogg.h0000664000175000001440000001061710210123147013661 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef OGG_H__ #define OGG_H__ #include "buf.h" #include "crc32.h" #include "file.h" /* ogg header: 0 'O' 1 'g' 2 'g' 3 'S' 4 0x00 5 bit 1 = 0 (fresh), 1 (set) bit 2 = 0 (not first page), 1 (first page) bit 3 = 0 (not last page), 1 (last page) 6-13 absolute granule position 14-17 stream serial number 18-21 page sequence no 22-25 page checksum 26 page_segments 27... page segment_table */ #define OGG_SYNC_HDR_SIZE 4 #define OGG_HDR_MIN_SIZE 27 #define OGG_CRC32_POLY (0x04c11db7) #define OGG_SYNC_HDR_BYTE1 'O' #define OGG_SYNC_HDR_BYTE2 'g' #define OGG_SYNC_HDR_BYTE3 'g' #define OGG_SYNC_HDR_BYTE4 'S' #define OGG_MAX_SYNC 40 typedef struct ogg_page_bits_s { /*M If set, the page contains a continued packet. **/ unsigned int continuation :1; /*M If set, the page is the first page of the logical bitstream. **/ unsigned int first :1; /*M If set, the page is the last page of the logical bitstream. **/ unsigned int last :1; } ogg_page_bits_t; typedef struct ogg_page_s { /*M Page flags. **/ ogg_page_bits_t b; /*M Absolute granule position. (This is packed in the same way the rest of Ogg data is packed; LSb of LSB first. Note that the 'position' data specifies a 'sample' number (eg, in a CD quality sample is four octets, 16 bits for left and 16 bits for right; in video it would likely be the frame number. It is up to the specific codec in use to define the semantic meaning of the granule position value). The position specified is the total samples encoded after including all packets finished on this page (packets begun on this page but continuing on to the next page do not count). The rationale here is that the position specified in the frame header of the last page tells how long the data coded by the bitstream is. A truncated stream will still return the proper number of samples that can be decoded fully. A special value of '-1' (in two's complement) indicates that no packets finish on this page. **/ unsigned char position[8]; /*M Stream serial number. Ogg allows for separate logical bitstreams to be mixed at page granularity in a physical bitstream. The most common case would be sequential arrangement, but it is possible to interleave pages for two separate bitstreams to be decoded concurrently. The serial number is the means by which pages physical pages are associated with a particular logical stream. Each logical stream must have a unique serial number within a physical stream: **/ unsigned long stream; /*M Page sequence number. Page counter: lets us know if a page is lost (useful where packets span page boundaries. **/ unsigned long page_no; /*M Page checksum. 32 bit CRC value (direct algorith, initial val and final XOR = 0, generator polynomial = 0x04c11db7). The value is computed over the entire header (with the CRC field in the header set to zero) and then continued over the page. The CRC field is then filled with the computed value. **/ unsigned long page_cksum; /*M Page segments. The number of segment entries to appear in the segment table. The maximum number of 255 segments (255 bytes each) sets the maximum possible physical page size at 65307 bytes or just under 64kB (thus we know that a header corrupted so as destroy sizing/alignment information will not cause a runaway bitstream. We'll read in the page according to the corrupted size information that's guaranteed to be a reasonable size regardless, notice the checksum mismatch, drop sync and then look for recapture). **/ unsigned char page_segments; /*M Segment table (containing packet lacing values). XXX: do we need the whole table? We could do with the lacing value of the last segment. **/ unsigned char lacing_values[255]; unsigned long size; buf_t raw; } ogg_page_t; void ogg_page_init(ogg_page_t *page); void ogg_page_destroy(ogg_page_t *page); int ogg_write_page(file_t *ogg, ogg_page_t *page); int ogg_next_page(file_t *ogg, ogg_page_t *page); extern crc32_t ogg_crc32; void ogg_init(void); unsigned char *ogg_segment(ogg_page_t *page, int num); unsigned long ogg_position_to_msecs(ogg_page_t *page, unsigned long sample_rate); #endif /* OGG_H__ */ /*C **/ poc-0.4.2/buf.h0000664000175000001440000000054010210123147013653 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef BUF_H__ #define BUF_H__ typedef struct buf_s { unsigned char *data; unsigned long len; unsigned long size; } buf_t; int buf_alloc(buf_t *buf, unsigned long size); int buf_grow(buf_t *buf); int buf_append(buf_t *buf, void *data, unsigned long len); void buf_free(buf_t *buf); #endif /* BUF_H__ */ /*C **/ poc-0.4.2/file.h0000664000175000001440000000134310210123147014020 0ustar manuelusers00000000000000/*C (c) 2005 bl0rg.net **/ #ifndef FILE_H__ #define FILE_H__ #include /*M \emph{Error returned by file_read and file_write.} **/ #define EEOF (-1) #define ESYNC (-2) typedef struct file_s { /*M File descriptor. **/ int fd; /*M Offset into file. **/ unsigned long offset; /*M Size of file. **/ unsigned long size; unsigned short maxsync; } file_t; int file_open_read(file_t *file, char *filename); int file_open_write(file_t *file, char *filename); int file_close(file_t *file); int file_read(file_t *file, unsigned char *buf, size_t size); int file_seek_fwd(file_t *file, size_t size); int file_write(file_t *file, unsigned char *buf, size_t size); #endif /* FILE_H__ */ /*C **/ poc-0.4.2/misc.c0000664000175000001440000000171610214014115014031 0ustar manuelusers00000000000000/* * (c) 2005 bl0rg.net * * Misc functions (mostly unix workarounds) */ #include #include #include #include "misc.h" int unix_write(int fd, unsigned char *buf, size_t size) { int i, len = 0; while ((i = write(fd, buf + len, size - len))) { if (i < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else { perror("write"); return -1; } } else { len += i; if (len == size) break; } } if (i == 0) return 0; else return len; } int unix_read(int fd, unsigned char *buf, size_t size) { int i, len = 0; while ((i = read(fd, buf + len, size - len))) { if (i < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else { perror("read"); return -1; } } else { len += i; if (len == size) break; } } if (i == 0) return 0; else return len; }