/* * Miscellaneous useful functions. * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the MPEG TS, PS and ES tools. * * The Initial Developer of the Original Code is Amino Communications Ltd. * Portions created by the Initial Developer are Copyright (C) 2008 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Amino Communications Ltd, Swavesey, Cambridge UK * * ***** END LICENSE BLOCK ***** */ #ifndef _misc_fns #define _misc_fns #include "misc_defns.h" #include "es_defns.h" #ifndef _WIN32 #include #endif #ifdef _WIN32 #include "compat.h" #include #endif // _WIN32 #define CRC32_POLY 0x04c11db7L /* * Compute CRC32 over a block of data, by table method. * * Returns a working value, suitable for re-input for further blocks * * Notes: Input value should be 0xffffffff for the first block, * else return value from previous call (not sure if that * needs complementing before being passed back in). */ extern uint32_t crc32_block(uint32_t crc, byte *pData, int blk_len); /* * Print out the bottom N bits from a byte */ extern void print_bits(int num_bits, byte value); /* * Print out (the first `max`) bytes of a byte array. * * - if `is_msg` then print as a message, otherwise as an error * - `name` is identifying text to start the report with. * - `data` is the byte data to print. This may be NULL. * - `length` is its length * - `max` is the maximum number of bytes to print * * Prints out:: * * (): b1 b2 b3 b4 ... * * where no more than `max` bytes are to be printed (and "..." is printed * if not all bytes were shown). */ extern void print_data(int is_msg, const char *name, const byte data[], int length, int max); /* * Print out (the last `max`) bytes of a byte array. * * - `name` is identifying text to start the report with. * - `data` is the byte data to print. This may be NULL. * - `length` is its length * - `max` is the maximum number of bytes to print * * Prints out:: * * (): ... b1 b2 b3 b4 * * where no more than `max` bytes are to be printed (and "..." is printed * if not all bytes were shown). */ extern void print_end_of_data(char *name, byte data[], int length, int max); /* * Calculate log2 of `x` - for some reason this is missing from */ extern double log2(double x); // ============================================================ // Simple file I/O utilities // ============================================================ /* * Read a given number of bytes from a file. * * This is a jacket for `read`, allowing for the future possibility of * buffered input, and simplifying error handling. * * - `input` is the file descriptor for the file * - `num_bytes` is how many bytes to read * - `data` is the buffer to read the bytes into * * Returns 0 if all goes well, EOF if end of file was read, or 1 if some * other error occurred (in which case it will already have output a message * on stderr about the problem). */ extern int read_bytes(int input, int num_bytes, byte *data); /* * Utility function to seek within a file * * - `filedes` is the file to seek within * - `posn` is the position to which to seek * * This is a jacket for:: * * new_posn = lseek(filedes,posn,SEEK_SET); * * Returns 0 if all went well, 1 if the seek failed (either because * it returned -1, or because the position reached was not the position * requested). If an error occurs, then an explanatory message will * already have been written to stderr. */ extern int seek_file(int filedes, offset_t posn); /* * Utility function to report the current location within a file * * - `filedes` is the file to seek within * * This is a jacket for:: * * posn = lseek(filedes,0,SEEK_CUR); * * Returns the current position in the file if all went well, otherwise * -1 (in which case an error message will already have been written * on stderr) */ extern offset_t tell_file(int filedes); /* * Utility function to open a file (descriptor), and report any errors * * This is intended only for very simple usage, and is not mean to be * a general purpose "open" replacement. * * - `filename` is the name of the file to open * - `for_write` should be TRUE if the file is to be written to, * in which case it will be opened with flags O_WRONLY|O_CREAT|O_TRUNC, * or FALSE if the file is to be read, in which case it will be * opened with flag O_RDONLY. In both cases, on Windows the flag * O_BINARY will also be set. * * Returns the file descriptor for the file, or -1 if it failed to open * the file. */ extern int open_binary_file(char *filename, int for_write); /* * Utility function to close a file (descriptor), and report any errors * * Returns 0 if all went well, 1 if an error occurred. */ extern int close_file(int filedes); // ============================================================ // More complex file I/O utilities // ============================================================ /* * Open an input file appropriately for reading as ES. * * - `name` is the name of the file, or NULL if standard input * is to be read from (which is not allowed if `use_pes` is * TRUE). * * - If `use_pes` is true then the input file is PS or TS and should * be read via a PES reader. * * - If `quiet` is true then information about the file being read will * not be written out. Otherwise, its name and what is decided about * its content will be printed. * * - If `force_stream_type` is true, then the caller asserts that * the input shall be read according to `want_data`, and not whatever * might be deduced from looking at the file itself. * * - If `force_stream_type` is true, then `want_data` should be one of * VIDEO_H262, VIDEO_H264 or VIDEO_AVS. `is_data` will then be * returned with the same value. * * - If `force_stream_type` is false, then the function will attempt * to determine what type of data it has, and `is_data` will be set * to whatever is determined (presumably one of VIDEO_H262, VIDEO_H264 * or VIDEO_AVS). * * - If input is from standard input, and `force_stream_type` is FALSE, * `is_data` will always be set to VIDEO_H262, which may be incorrect. * * - `es` is the new ES reader context. * * Returns 0 if all goes well, 1 if something goes wrong. In the latter case, * suitable messages will have been written out to standard error. */ extern int open_input_as_ES(char *name, int use_pes, int quiet, int force_stream_type, int want_data, int *is_data, ES_p *es); /* * Close an input ES stream opened with `open_input_as_ES`. * * Specifically, this will close the ES stream and also any underlying PES * reader and file (unless the input was standard input). * * - `name` is the name of the file, used for error reporting. * - `es` is the ES stream to close. This will be set to NULL. * * Returns 0 if all goes well, 1 if something goes wrong. In the latter case, * suitable messages will have been written out to standard error. */ extern int close_input_as_ES(char *name, ES_p *es); // ============================================================ // Command line "helpers" // ============================================================ /* * Read in an unsigned integer value, checking for extraneous characters. * * - `prefix` is an optional prefix for error messages, typically the * name of the program. It may be NULL. * - `cmd` is the command switch we're reading for (typically ``argv[ii]``), * which is used in error messages. * - `str` is the string to read (typically ``argv[ii+1]``). * - `base` is the base to read to. If it is 0, then the user can use * C-style expressions like "0x68" to specify the base on the command line. * - `value` is the value read. * * Returns 0 if all went well, 1 otherwise (in which case a message * explaining will have been written to stderr). */ extern int unsigned_value(char *prefix, char *cmd, char *arg, int base, uint32_t *value); /* * Read in an integer value, checking for extraneous characters. * * - `prefix` is an optional prefix for error messages, typically the * name of the program. It may be NULL. * - `cmd` is the command switch we're reading for (typically ``argv[ii]``), * which is used in error messages. * - `str` is the string to read (typically ``argv[ii+1]``). * - if `positive` is true, then the number read must be positive (0 or more). * - `base` is the base to read to. If it is 0, then the user can use * C-style expressions like "0x68" to specify the base on the command line. * - `value` is the value read. * * Returns 0 if all went well, 1 otherwise (in which case a message * explaining will have been written to stderr). */ extern int int_value(char *prefix, char *cmd, char *str, int positive, int base, int *value); /* * Read in an integer value, checking for extraneous characters and a range. * * - `prefix` is an optional prefix for error messages, typically the * name of the program. It may be NULL. * - `cmd` is the command switch we're reading for (typically ``argv[ii]``), * which is used in error messages. * - `str` is the string to read (typically ``argv[ii+1]``). * - `minimum` is the minimum value allowed. * - `maximum` is the maximum value allowed. * - `base` is the base to read to. If it is 0, then the user can use * C-style expressions like "0x68" to specify the base on the command line. * - `value` is the value read. * * Returns 0 if all went well, 1 otherwise (in which case a message * explaining will have been written to stderr). */ extern int int_value_in_range(char *prefix, char *cmd, char *arg, int minimum, int maximum, int base, int *value); /* * Read in a double value, checking for extraneous characters. * * - `prefix` is an optional prefix for error messages, typically the * name of the program. It may be NULL. * - `cmd` is the command switch we're reading for (typically ``argv[ii]``), * which is used in error messages. * - `str` is the string to read (typically ``argv[ii+1]``). * - if `positive` is true, then the number read must be positive (0 or more). * - `value` is the value read. * * Returns 0 if all went well, 1 otherwise (in which case a message * explaining will have been written to stderr). */ extern int double_value(char *prefix, char *cmd, char *arg, int positive, double *value); /* * Read in a hostname and (optional) port * * - `prefix` is an optional prefix for error messages, typically the * name of the program. It may be NULL. * - `cmd` is the command switch we're reading for (typically ``argv[ii]``), * which is used in error messages. * - `arg` is the string to read (typically ``argv[ii+1]``). * - `hostname` is the host name read * - `port` is the port read (note that this is not touched if there is * no port number, so it may be set to a default before calling this * function) * * Note that this works by pointing `hostname` to the start of the `arg` * string, and then if there is a ':' in `arg`, changing that colon to * a '\0' delimiter, and interpreting the string thereafter as the port * number. If *that* fails, it resets the '\0' as a ':'. * * Returns 0 if all went well, 1 otherwise (in which case a message * explaining will have been written to stderr). */ extern int host_value(char *prefix, char *cmd, char *arg, char **hostname, int *port); // ============================================================ // Sockets // ============================================================ #ifdef _WIN32 /* * Start up WINSOCK so we can use sockets. * * Note that each successful call of this *must* be matched by a call * of winsock_cleanup(). * * Returns 0 if it works, 1 if it fails. */ extern int winsock_startup(void); /* * Convert a WinSock error number into a string and print it out on stderr */ extern void print_winsock_err(int err); #endif // _WIN32 /* * Connect to a socket, to allow us to write to it, using TCP/IP. * * - `hostname` is the name of the host to connect to * - `port` is the port to use * - if `use_tcpip`, then a TCP/IP connection will be made, otherwise UDP. * For UDP, multicast TTL will be enabled. * - If the destination address (`hostname`) is multicast and `multicast_ifaddr` * is supplied, it is used to select (by IP address) the network interface * on which to send the multicasts. It may be NULL to use the default, * or for non-multicast cases. * * A socket connected to via this function must be disconnected from with * disconnect_socket(). * * Returns a positive integer (the file descriptor for the socket) if it * succeeds, or -1 if it fails, in which case it will have complained on * stderr. */ extern int connect_socket(char *hostname, int port, int use_tcpip, char *multicast_ifaddr); /* * Disconnect from a socket (close it). * * Returns 0 if all goes well, 1 otherwise. */ #ifdef _WIN32 extern int disconnect_socket(SOCKET socket); #else // _WIN32 extern int disconnect_socket(int socket); #endif // _WIN32 /*! Decode a host byte order address to a static buffer. */ const char *ipv4_addr_to_string(const uint32_t addr); /*! Decode a string to a host byte order address */ int ipv4_string_to_addr(uint32_t *dest, const char *addr); // ============================================================ // Byte order handling // ============================================================ static inline uint32_t uint_32_be(const uint8_t *const p) { return (((int)p[0]&0xff) << 24) | (((int)p[1]&0xff) << 16) | (((int)p[2]&0xff) << 8) | (((int)p[3]&0xff)); } static inline uint32_t uint_32_le(const uint8_t *const p) { return (((int)p[0]&0xff) | (((int)p[1]&0xff) << 8) | (((int)p[2]&0xff) << 16) | (((int)p[3]&0xff) << 24)); } static inline uint16_t uint_16_be(const uint8_t *const p) { return ((((int)p[0])&0xff)<<8) | ((((int)p[1])&0xff)); } static inline uint16_t uint_16_le(const uint8_t *const p) { return (((int)p[0]&0xff) | ((int)p[1]&0xff)<<8); } // ============================================================ // Time diffs // ============================================================ #define PCR_UNSIGNED_WRAP (300ULL * (1ULL << 33)) // (x - y) with allowance for PCR wrap - unsigned version static inline uint64_t pcr_unsigned_diff(uint64_t x, uint64_t y) { return x > y ? x - y : 300ULL * (1ULL << 33) - (y - x); } #define PCR_SIGNED_WRAP (300LL * (1LL << 33)) #define PCR_SIGNED_MAX (PCR_SIGNED_WRAP / 2LL - 1LL) #define PCR_SIGNED_MIN (-PCR_SIGNED_WRAP / 2LL) // (x - y) with allowance for PCR wrap - signed version static inline int64_t pcr_signed_diff(uint64_t x, uint64_t y) { int64_t r = x - y; return r < PCR_SIGNED_MIN ? r + PCR_SIGNED_WRAP : r > PCR_SIGNED_MAX ? r - PCR_SIGNED_WRAP : r; } // Deal with simple overflow static inline uint64_t pcr_unsigned_wrap(uint64_t x) { return x >= PCR_UNSIGNED_WRAP ? x - PCR_UNSIGNED_WRAP : x; } static inline int64_t pts_signed_diff(uint64_t x, uint64_t y) { int64_t r = x - y; return (r << 31) >> 31; } #endif // _misc_fns // Local Variables: // tab-width: 8 // indent-tabs-mode: nil // c-basic-offset: 2 // End: // vim: set tabstop=8 shiftwidth=2 expandtab: