/* * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * multiple format streaming server based on the FFmpeg libraries */ #include "config.h"#if !HAVE_CLOSESOCKET#define closesocket close#endif#include <string.h>#include <stdlib.h>#include <stdio.h>#include "libavformat/avformat.h"/* FIXME: those are internal headers, ffserver _really_ shouldn't use them */#include "libavformat/rtpproto.h"#include "libavformat/rtsp.h"#include "libavformat/avio_internal.h"#include "libavformat/internal.h" #include "libavutil/avassert.h"#include "libavutil/avstring.h"#include "libavutil/lfg.h"#include "libavutil/dict.h"#include "libavutil/intreadwrite.h"#include "libavutil/mathematics.h"#include "libavutil/random_seed.h"#include "libavutil/rational.h"#include "libavutil/parseutils.h"#include "libavutil/opt.h"#include "libavutil/time.h" #include <stdarg.h>#if HAVE_UNISTD_H#include <unistd.h>#endif#include <fcntl.h>#include <sys/ioctl.h>#if HAVE_POLL_H#include <poll.h>#endif#include <errno.h>#include <time.h>#include <sys/wait.h>#include <signal.h> #include "cmdutils.h"#include "ffserver_config.h" #define PATH_LENGTH 1024 const char program_name[] = "ffserver";const int program_birth_year = 2000; static const OptionDef options[]; enum HTTPState { HTTPSTATE_WAIT_REQUEST, HTTPSTATE_SEND_HEADER, HTTPSTATE_SEND_DATA_HEADER, HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */ HTTPSTATE_SEND_DATA_TRAILER, HTTPSTATE_RECEIVE_DATA, HTTPSTATE_WAIT_FEED, /* wait for data from the feed */ HTTPSTATE_READY, RTSPSTATE_WAIT_REQUEST, RTSPSTATE_SEND_REPLY, RTSPSTATE_SEND_PACKET,}; static const char * const http_state[] = { "HTTP_WAIT_REQUEST", "HTTP_SEND_HEADER", "SEND_DATA_HEADER", "SEND_DATA", "SEND_DATA_TRAILER", "RECEIVE_DATA", "WAIT_FEED", "READY", "RTSP_WAIT_REQUEST", "RTSP_SEND_REPLY", "RTSP_SEND_PACKET",}; #define IOBUFFER_INIT_SIZE 8192 /* timeouts are in ms */#define HTTP_REQUEST_TIMEOUT (15 * 1000)#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000) #define SYNC_TIMEOUT (10 * 1000) typedef struct RTSPActionServerSetup { uint32_t ipaddr; char transport_option[512];} RTSPActionServerSetup; typedef struct { int64_t count1, count2; int64_t time1, time2;} DataRateData; /* context associated with one connection */typedef struct HTTPContext { enum HTTPState state; int fd; /* socket file descriptor */ struct sockaddr_in from_addr; /* origin */ struct pollfd *poll_entry; /* used when polling */ int64_t timeout; uint8_t *buffer_ptr, *buffer_end; int http_error; int post; int chunked_encoding; int chunk_size; /* 0 if it needs to be read */ struct HTTPContext *next; int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */ int64_t data_count; /* feed input */ int feed_fd; /* input format handling */ AVFormatContext *fmt_in; int64_t start_time; /* In milliseconds - this wraps fairly often */ int64_t first_pts; /* initial pts value */ int64_t cur_pts; /* current pts value from the stream in us */ int64_t cur_frame_duration; /* duration of the current frame in us */ int cur_frame_bytes; /* output frame size, needed to compute the time at which we send each packet */ int pts_stream_index; /* stream we choose as clock reference */ int64_t cur_clock; /* current clock reference value in us */ /* output format handling */ struct FFServerStream *stream; /* -1 is invalid stream */ int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ int switch_pending; AVFormatContext *pfmt_ctx; /* instance of FFServerStream for one user */ int last_packet_sent; /* true if last data packet was sent */ int suppress_log; DataRateData datarate; int wmp_client_id; char protocol[16]; char method[16]; char url[128]; char clean_url[128*7]; int buffer_size; uint8_t *buffer; int is_packetized; /* if true, the stream is packetized */ int packet_stream_index; /* current stream for output in state machine */ /* RTSP state specific */ uint8_t *pb_buffer; /* XXX: use that in all the code */ AVIOContext *pb; int seq; /* RTSP sequence number */ /* RTP state specific */ enum RTSPLowerTransport rtp_protocol; char session_id[32]; /* session id */ AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS]; /* RTP/UDP specific */ URLContext *rtp_handles[FFSERVER_MAX_STREAMS]; /* RTP/TCP specific */ struct HTTPContext *rtsp_c; uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;} HTTPContext; static HTTPContext *first_http_ctx; static FFServerConfig config = { .nb_max_http_connections = 2000, .nb_max_connections = 5, .max_bandwidth = 1000, .use_defaults = 1,}; static void new_connection(int server_fd, int is_rtsp);static void close_connection(HTTPContext *c); /* HTTP handling */static int handle_connection(HTTPContext *c);static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream);static void compute_status(HTTPContext *c);static int open_input_stream(HTTPContext *c, const char *info);static int http_parse_request(HTTPContext *c);static int http_send_data(HTTPContext *c);static int http_start_receive_data(HTTPContext *c);static int http_receive_data(HTTPContext *c); /* RTSP handling */static int rtsp_parse_request(HTTPContext *c);static void rtsp_cmd_describe(HTTPContext *c, const char *url);static void rtsp_cmd_options(HTTPContext *c, const char *url);static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only); /* SDP handling */static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer, struct in_addr my_ip); /* RTP handling */static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, FFServerStream *stream, const char *session_id, enum RTSPLowerTransport rtp_protocol);static int rtp_new_av_stream(HTTPContext *c, int stream_index, struct sockaddr_in *dest_addr, HTTPContext *rtsp_c);/* utils */static size_t htmlencode (const char *src, char **dest);static inline void cp_html_entity (char *buffer, const char *entity);static inline int check_codec_match(LayeredAVStream *ccf, AVStream *ccs, int stream); static const char *my_program_name; static int no_launch;static int need_to_start_children; /* maximum number of simultaneous HTTP connections */static unsigned int nb_connections; static uint64_t current_bandwidth; /* Making this global saves on passing it around everywhere */static int64_t cur_time; static AVLFG random_state; static FILE *logfile = NULL; static void unlayer_stream(AVStream *st, LayeredAVStream *lst){ avcodec_free_context(&st->codec); avcodec_parameters_free(&st->codecpar);#define COPY(a) st->a = lst->a; COPY(index) COPY(id) COPY(codec) COPY(codecpar) COPY(time_base) COPY(pts_wrap_bits) COPY(sample_aspect_ratio) COPY(recommended_encoder_configuration)} static inline void cp_html_entity (char *buffer, const char *entity) { if (!buffer || !entity) return; while (*entity) *buffer++ = *entity++;} /** * Substitutes known conflicting chars on a text string with * their corresponding HTML entities. * * Returns the number of bytes in the 'encoded' representation * not including the terminating NUL. */static size_t htmlencode (const char *src, char **dest) { const char *amp = "&"; const char *lt = "<"; const char *gt = ">"; const char *start; char *tmp; size_t final_size = 0; if (!src) return 0; start = src; /* Compute needed dest size */ while (*src != '\0') { switch(*src) { case 38: /* & */ final_size += 5; break; case 60: /* < */ case 62: /* > */ final_size += 4; break; default: final_size++; } src++; } src = start; *dest = av_mallocz(final_size + 1); if (!*dest) return 0; /* Build dest */ tmp = *dest; while (*src != '\0') { switch(*src) { case 38: /* & */ cp_html_entity (tmp, amp); tmp += 5; break; case 60: /* < */ cp_html_entity (tmp, lt); tmp += 4; break; case 62: /* > */ cp_html_entity (tmp, gt); tmp += 4; break; default: *tmp = *src; tmp += 1; } src++; } *tmp = '\0'; return final_size;} static int64_t ffm_read_write_index(int fd){ uint8_t buf[8]; if (lseek(fd, 8, SEEK_SET) < 0) return AVERROR(EIO); if (read(fd, buf, 8) != 8) return AVERROR(EIO); return AV_RB64(buf);} static int ffm_write_write_index(int fd, int64_t pos){ uint8_t buf[8]; int i; for(i=0;i<8;i++) buf[i] = (pos >> (56 - i * 8)) & 0xff; if (lseek(fd, 8, SEEK_SET) < 0) goto bail_eio; if (write(fd, buf, 8) != 8) goto bail_eio; return 8; bail_eio: return AVERROR(EIO);} static void ffm_set_write_index(AVFormatContext *s, int64_t pos, int64_t file_size){ av_opt_set_int(s, "server_attached", 1, AV_OPT_SEARCH_CHILDREN); av_opt_set_int(s, "ffm_write_index", pos, AV_OPT_SEARCH_CHILDREN); av_opt_set_int(s, "ffm_file_size", file_size, AV_OPT_SEARCH_CHILDREN);} static char *ctime1(char *buf2, size_t buf_size){ time_t ti; char *p; ti = time(NULL); p = ctime(&ti); if (!p || !*p) { *buf2 = '\0'; return buf2; } av_strlcpy(buf2, p, buf_size); p = buf2 + strlen(buf2) - 1; if (*p == '\n') *p = '\0'; return buf2;} static void http_vlog(const char *fmt, va_list vargs){ static int print_prefix = 1; char buf[32]; if (!logfile) return; if (print_prefix) { ctime1(buf, sizeof(buf)); fprintf(logfile, "%s ", buf); } print_prefix = strstr(fmt, "\n") != NULL; vfprintf(logfile, fmt, vargs); fflush(logfile);} #ifdef __GNUC____attribute__ ((format (printf, 1, 2)))#endifstatic void http_log(const char *fmt, ...){ va_list vargs; va_start(vargs, fmt); http_vlog(fmt, vargs); va_end(vargs);} static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs){ static int print_prefix = 1; AVClass *avc = ptr ? *(AVClass**)ptr : NULL; if (level > av_log_get_level()) return; if (print_prefix && avc) http_log("[%s @ %p]", avc->item_name(ptr), ptr); print_prefix = strstr(fmt, "\n") != NULL; http_vlog(fmt, vargs);} static void log_connection(HTTPContext *c){ if (c->suppress_log) return; http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n", inet_ntoa(c->from_addr.sin_addr), c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count);} static void update_datarate(DataRateData *drd, int64_t count){ if (!drd->time1 && !drd->count1) { drd->time1 = drd->time2 = cur_time; drd->count1 = drd->count2 = count; } else if (cur_time - drd->time2 > 5000) { drd->time1 = drd->time2; drd->count1 = drd->count2; drd->time2 = cur_time; drd->count2 = count; }} /* In bytes per second */static int compute_datarate(DataRateData *drd, int64_t count){ if (cur_time == drd->time1) return 0; return ((count - drd->count1) * 1000) / (cur_time - drd->time1);} static void start_children(FFServerStream *feed){ char *pathname; char *slash; int i; size_t cmd_length; if (no_launch) return; cmd_length = strlen(my_program_name); /** * FIXME: WIP Safeguard. Remove after clearing all harcoded * '1024' path lengths */ if (cmd_length > PATH_LENGTH - 1) { http_log("Could not start children. Command line: '%s' exceeds " "path length limit (%d)\n", my_program_name, PATH_LENGTH); return; } slash = strrchr(my_program_name, '/'); if (!slash) { pathname = av_mallocz(sizeof("ffmpeg"));Lines 1–500 of 4026. Load more
/* * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * multiple format streaming server based on the FFmpeg libraries */ #include "config.h" #if !HAVE_CLOSESOCKET #define closesocket close #endif #include <string.h> #include <stdlib.h> #include <stdio.h> #include "libavformat/avformat.h" /* FIXME: those are internal headers, ffserver _really_ shouldn't use them */ #include "libavformat/rtpproto.h" #include "libavformat/rtsp.h" #include "libavformat/avio_internal.h" #include "libavformat/internal.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/lfg.h" #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/random_seed.h" #include "libavutil/rational.h" #include "libavutil/parseutils.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include <stdarg.h> #if HAVE_UNISTD_H #include <unistd.h> #endif #include <fcntl.h> #include <sys/ioctl.h> #if HAVE_POLL_H #include <poll.h> #endif #include <errno.h> #include <time.h> #include <sys/wait.h> #include <signal.h> #include "cmdutils.h" #include "ffserver_config.h" #define PATH_LENGTH 1024 const char program_name[] = "ffserver"; const int program_birth_year = 2000; static const OptionDef options[]; enum HTTPState { HTTPSTATE_WAIT_REQUEST, HTTPSTATE_SEND_HEADER, HTTPSTATE_SEND_DATA_HEADER, HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */ HTTPSTATE_SEND_DATA_TRAILER, HTTPSTATE_RECEIVE_DATA, HTTPSTATE_WAIT_FEED, /* wait for data from the feed */ HTTPSTATE_READY, RTSPSTATE_WAIT_REQUEST, RTSPSTATE_SEND_REPLY, RTSPSTATE_SEND_PACKET, }; static const char * const http_state[] = { "HTTP_WAIT_REQUEST", "HTTP_SEND_HEADER", "SEND_DATA_HEADER", "SEND_DATA", "SEND_DATA_TRAILER", "RECEIVE_DATA", "WAIT_FEED", "READY", "RTSP_WAIT_REQUEST", "RTSP_SEND_REPLY", "RTSP_SEND_PACKET", }; #define IOBUFFER_INIT_SIZE 8192 /* timeouts are in ms */ #define HTTP_REQUEST_TIMEOUT (15 * 1000) #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000) #define SYNC_TIMEOUT (10 * 1000) typedef struct RTSPActionServerSetup { uint32_t ipaddr; char transport_option[512]; } RTSPActionServerSetup; typedef struct { int64_t count1, count2; int64_t time1, time2; } DataRateData; /* context associated with one connection */ typedef struct HTTPContext { enum HTTPState state; int fd; /* socket file descriptor */ struct sockaddr_in from_addr; /* origin */ struct pollfd *poll_entry; /* used when polling */ int64_t timeout; uint8_t *buffer_ptr, *buffer_end; int http_error; int post; int chunked_encoding; int chunk_size; /* 0 if it needs to be read */ struct HTTPContext *next; int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */ int64_t data_count; /* feed input */ int feed_fd; /* input format handling */ AVFormatContext *fmt_in; int64_t start_time; /* In milliseconds - this wraps fairly often */ int64_t first_pts; /* initial pts value */ int64_t cur_pts; /* current pts value from the stream in us */ int64_t cur_frame_duration; /* duration of the current frame in us */ int cur_frame_bytes; /* output frame size, needed to compute the time at which we send each packet */ int pts_stream_index; /* stream we choose as clock reference */ int64_t cur_clock; /* current clock reference value in us */ /* output format handling */ struct FFServerStream *stream; /* -1 is invalid stream */ int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ int switch_pending; AVFormatContext *pfmt_ctx; /* instance of FFServerStream for one user */ int last_packet_sent; /* true if last data packet was sent */ int suppress_log; DataRateData datarate; int wmp_client_id; char protocol[16]; char method[16]; char url[128]; char clean_url[128*7]; int buffer_size; uint8_t *buffer; int is_packetized; /* if true, the stream is packetized */ int packet_stream_index; /* current stream for output in state machine */ /* RTSP state specific */ uint8_t *pb_buffer; /* XXX: use that in all the code */ AVIOContext *pb; int seq; /* RTSP sequence number */ /* RTP state specific */ enum RTSPLowerTransport rtp_protocol; char session_id[32]; /* session id */ AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS]; /* RTP/UDP specific */ URLContext *rtp_handles[FFSERVER_MAX_STREAMS]; /* RTP/TCP specific */ struct HTTPContext *rtsp_c; uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end; } HTTPContext; static HTTPContext *first_http_ctx; static FFServerConfig config = { .nb_max_http_connections = 2000, .nb_max_connections = 5, .max_bandwidth = 1000, .use_defaults = 1, }; static void new_connection(int server_fd, int is_rtsp); static void close_connection(HTTPContext *c); /* HTTP handling */ static int handle_connection(HTTPContext *c); static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream); static void compute_status(HTTPContext *c); static int open_input_stream(HTTPContext *c, const char *info); static int http_parse_request(HTTPContext *c); static int http_send_data(HTTPContext *c); static int http_start_receive_data(HTTPContext *c); static int http_receive_data(HTTPContext *c); /* RTSP handling */ static int rtsp_parse_request(HTTPContext *c); static void rtsp_cmd_describe(HTTPContext *c, const char *url); static void rtsp_cmd_options(HTTPContext *c, const char *url); static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h); static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h); static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only); /* SDP handling */ static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer, struct in_addr my_ip); /* RTP handling */ static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, FFServerStream *stream, const char *session_id, enum RTSPLowerTransport rtp_protocol); static int rtp_new_av_stream(HTTPContext *c, int stream_index, struct sockaddr_in *dest_addr, HTTPContext *rtsp_c); /* utils */ static size_t htmlencode (const char *src, char **dest); static inline void cp_html_entity (char *buffer, const char *entity); static inline int check_codec_match(LayeredAVStream *ccf, AVStream *ccs, int stream); static const char *my_program_name; static int no_launch; static int need_to_start_children; /* maximum number of simultaneous HTTP connections */ static unsigned int nb_connections; static uint64_t current_bandwidth; /* Making this global saves on passing it around everywhere */ static int64_t cur_time; static AVLFG random_state; static FILE *logfile = NULL; static void unlayer_stream(AVStream *st, LayeredAVStream *lst) { avcodec_free_context(&st->codec); avcodec_parameters_free(&st->codecpar); #define COPY(a) st->a = lst->a; COPY(index) COPY(id) COPY(codec) COPY(codecpar) COPY(time_base) COPY(pts_wrap_bits) COPY(sample_aspect_ratio) COPY(recommended_encoder_configuration) } static inline void cp_html_entity (char *buffer, const char *entity) { if (!buffer || !entity) return; while (*entity) *buffer++ = *entity++; } /** * Substitutes known conflicting chars on a text string with * their corresponding HTML entities. * * Returns the number of bytes in the 'encoded' representation * not including the terminating NUL. */ static size_t htmlencode (const char *src, char **dest) { const char *amp = "&"; const char *lt = "<"; const char *gt = ">"; const char *start; char *tmp; size_t final_size = 0; if (!src) return 0; start = src; /* Compute needed dest size */ while (*src != '\0') { switch(*src) { case 38: /* & */ final_size += 5; break; case 60: /* < */ case 62: /* > */ final_size += 4; break; default: final_size++; } src++; } src = start; *dest = av_mallocz(final_size + 1); if (!*dest) return 0; /* Build dest */ tmp = *dest; while (*src != '\0') { switch(*src) { case 38: /* & */ cp_html_entity (tmp, amp); tmp += 5; break; case 60: /* < */ cp_html_entity (tmp, lt); tmp += 4; break; case 62: /* > */ cp_html_entity (tmp, gt); tmp += 4; break; default: *tmp = *src; tmp += 1; } src++; } *tmp = '\0'; return final_size; } static int64_t ffm_read_write_index(int fd) { uint8_t buf[8]; if (lseek(fd, 8, SEEK_SET) < 0) return AVERROR(EIO); if (read(fd, buf, 8) != 8) return AVERROR(EIO); return AV_RB64(buf); } static int ffm_write_write_index(int fd, int64_t pos) { uint8_t buf[8]; int i; for(i=0;i<8;i++) buf[i] = (pos >> (56 - i * 8)) & 0xff; if (lseek(fd, 8, SEEK_SET) < 0) goto bail_eio; if (write(fd, buf, 8) != 8) goto bail_eio; return 8; bail_eio: return AVERROR(EIO); } static void ffm_set_write_index(AVFormatContext *s, int64_t pos, int64_t file_size) { av_opt_set_int(s, "server_attached", 1, AV_OPT_SEARCH_CHILDREN); av_opt_set_int(s, "ffm_write_index", pos, AV_OPT_SEARCH_CHILDREN); av_opt_set_int(s, "ffm_file_size", file_size, AV_OPT_SEARCH_CHILDREN); } static char *ctime1(char *buf2, size_t buf_size) { time_t ti; char *p; ti = time(NULL); p = ctime(&ti); if (!p || !*p) { *buf2 = '\0'; return buf2; } av_strlcpy(buf2, p, buf_size); p = buf2 + strlen(buf2) - 1; if (*p == '\n') *p = '\0'; return buf2; } static void http_vlog(const char *fmt, va_list vargs) { static int print_prefix = 1; char buf[32]; if (!logfile) return; if (print_prefix) { ctime1(buf, sizeof(buf)); fprintf(logfile, "%s ", buf); } print_prefix = strstr(fmt, "\n") != NULL; vfprintf(logfile, fmt, vargs); fflush(logfile); } #ifdef __GNUC__ __attribute__ ((format (printf, 1, 2))) #endif static void http_log(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); http_vlog(fmt, vargs); va_end(vargs); } static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs) { static int print_prefix = 1; AVClass *avc = ptr ? *(AVClass**)ptr : NULL; if (level > av_log_get_level()) return; if (print_prefix && avc) http_log("[%s @ %p]", avc->item_name(ptr), ptr); print_prefix = strstr(fmt, "\n") != NULL; http_vlog(fmt, vargs); } static void log_connection(HTTPContext *c) { if (c->suppress_log) return; http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n", inet_ntoa(c->from_addr.sin_addr), c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count); } static void update_datarate(DataRateData *drd, int64_t count) { if (!drd->time1 && !drd->count1) { drd->time1 = drd->time2 = cur_time; drd->count1 = drd->count2 = count; } else if (cur_time - drd->time2 > 5000) { drd->time1 = drd->time2; drd->count1 = drd->count2; drd->time2 = cur_time; drd->count2 = count; } } /* In bytes per second */ static int compute_datarate(DataRateData *drd, int64_t count) { if (cur_time == drd->time1) return 0; return ((count - drd->count1) * 1000) / (cur_time - drd->time1); } static void start_children(FFServerStream *feed) { char *pathname; char *slash; int i; size_t cmd_length; if (no_launch) return; cmd_length = strlen(my_program_name); /** * FIXME: WIP Safeguard. Remove after clearing all harcoded * '1024' path lengths */ if (cmd_length > PATH_LENGTH - 1) { http_log("Could not start children. Command line: '%s' exceeds " "path length limit (%d)\n", my_program_name, PATH_LENGTH); return; } slash = strrchr(my_program_name, '/'); if (!slash) { pathname = av_mallocz(sizeof("ffmpeg"));