| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Multiple format streaming server | 
					
						
							| 
									
										
										
										
											2002-05-25 22:26:19 +00:00
										 |  |  |  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-03-18 17:35:10 +00:00
										 |  |  |  * This file is part of Libav. | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-03-18 17:35:10 +00:00
										 |  |  |  * Libav is free software; you can redistribute it and/or | 
					
						
							| 
									
										
										
										
											2002-05-25 22:26:19 +00:00
										 |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-03-18 17:35:10 +00:00
										 |  |  |  * Libav is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2002-05-25 22:26:19 +00:00
										 |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2002-05-25 22:26:19 +00:00
										 |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							| 
									
										
										
										
											2011-03-18 17:35:10 +00:00
										 |  |  |  * License along with Libav; if not, write to the Free Software | 
					
						
							| 
									
										
										
										
											2006-01-12 22:43:26 +00:00
										 |  |  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-06-10 14:34:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-02 07:43:23 +00:00
										 |  |  | #include "config.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-13 23:44:16 +00:00
										 |  |  | #if !HAVE_CLOSESOCKET
 | 
					
						
							| 
									
										
										
										
											2007-07-02 07:43:23 +00:00
										 |  |  | #define closesocket close
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2008-08-13 17:22:53 +00:00
										 |  |  | #include <strings.h>
 | 
					
						
							| 
									
										
										
										
											2007-07-02 07:43:23 +00:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2008-05-09 11:56:36 +00:00
										 |  |  | #include "libavformat/avformat.h"
 | 
					
						
							| 
									
										
										
										
											2011-04-08 11:21:13 +02:00
										 |  |  | #include "libavformat/ffm.h"
 | 
					
						
							| 
									
										
										
										
											2008-05-09 11:56:36 +00:00
										 |  |  | #include "libavformat/network.h"
 | 
					
						
							|  |  |  | #include "libavformat/os_support.h"
 | 
					
						
							| 
									
										
										
										
											2009-02-06 10:35:52 +00:00
										 |  |  | #include "libavformat/rtpdec.h"
 | 
					
						
							| 
									
										
										
										
											2008-05-09 11:56:36 +00:00
										 |  |  | #include "libavformat/rtsp.h"
 | 
					
						
							| 
									
										
										
										
											2011-03-17 08:19:54 +01:00
										 |  |  | // XXX for ffio_open_dyn_packet_buffer, to be removed
 | 
					
						
							|  |  |  | #include "libavformat/avio_internal.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-13 23:36:06 +00:00
										 |  |  | #include "libavutil/avstring.h"
 | 
					
						
							| 
									
										
										
										
											2009-03-20 01:00:53 +00:00
										 |  |  | #include "libavutil/lfg.h"
 | 
					
						
							| 
									
										
										
										
											2011-05-22 12:46:29 +02:00
										 |  |  | #include "libavutil/dict.h"
 | 
					
						
							| 
									
										
										
										
											2011-06-04 12:58:23 +01:00
										 |  |  | #include "libavutil/mathematics.h"
 | 
					
						
							| 
									
										
										
										
											2009-03-20 01:00:53 +00:00
										 |  |  | #include "libavutil/random_seed.h"
 | 
					
						
							| 
									
										
										
										
											2011-02-07 14:37:08 +01:00
										 |  |  | #include "libavutil/parseutils.h"
 | 
					
						
							| 
									
										
										
										
											2011-02-03 14:58:59 +01:00
										 |  |  | #include "libavutil/opt.h"
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <sys/ioctl.h>
 | 
					
						
							| 
									
										
										
										
											2009-01-13 23:44:16 +00:00
										 |  |  | #if HAVE_POLL_H
 | 
					
						
							| 
									
										
										
										
											2008-02-13 12:51:14 +00:00
										 |  |  | #include <poll.h>
 | 
					
						
							| 
									
										
										
										
											2007-02-15 07:44:10 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <sys/time.h>
 | 
					
						
							|  |  |  | #include <time.h>
 | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | #include <sys/wait.h>
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | #include <signal.h>
 | 
					
						
							| 
									
										
										
										
											2009-01-13 23:44:16 +00:00
										 |  |  | #if HAVE_DLFCN_H
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | #include <dlfcn.h>
 | 
					
						
							| 
									
										
										
										
											2002-11-30 17:18:59 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-22 13:10:25 +00:00
										 |  |  | #include "cmdutils.h"
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | const char program_name[] = "avserver"; | 
					
						
							| 
									
										
										
										
											2008-05-29 08:48:51 +00:00
										 |  |  | const int program_birth_year = 2000; | 
					
						
							| 
									
										
										
										
											2007-09-27 06:38:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-21 17:55:54 +00:00
										 |  |  | static const OptionDef options[]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | enum HTTPState { | 
					
						
							|  |  |  |     HTTPSTATE_WAIT_REQUEST, | 
					
						
							|  |  |  |     HTTPSTATE_SEND_HEADER, | 
					
						
							|  |  |  |     HTTPSTATE_SEND_DATA_HEADER, | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     HTTPSTATE_SEND_DATA,          /* sending TCP or UDP data */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     HTTPSTATE_SEND_DATA_TRAILER, | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |     HTTPSTATE_RECEIVE_DATA, | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     HTTPSTATE_WAIT_FEED,          /* wait for data from the feed */ | 
					
						
							|  |  |  |     HTTPSTATE_READY, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RTSPSTATE_WAIT_REQUEST, | 
					
						
							|  |  |  |     RTSPSTATE_SEND_REPLY, | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     RTSPSTATE_SEND_PACKET, | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-21 03:21:29 +00:00
										 |  |  | static const char *http_state[] = { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     "HTTP_WAIT_REQUEST", | 
					
						
							|  |  |  |     "HTTP_SEND_HEADER", | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     "SEND_DATA_HEADER", | 
					
						
							|  |  |  |     "SEND_DATA", | 
					
						
							|  |  |  |     "SEND_DATA_TRAILER", | 
					
						
							|  |  |  |     "RECEIVE_DATA", | 
					
						
							|  |  |  |     "WAIT_FEED", | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     "READY", | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     "RTSP_WAIT_REQUEST", | 
					
						
							|  |  |  |     "RTSP_SEND_REPLY", | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     "RTSP_SEND_PACKET", | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-15 19:09:54 +00:00
										 |  |  | #define MAX_STREAMS 20
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | #define IOBUFFER_INIT_SIZE 8192
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* timeouts are in ms */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | #define HTTP_REQUEST_TIMEOUT (15 * 1000)
 | 
					
						
							|  |  |  | #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | #define SYNC_TIMEOUT (10 * 1000)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-05 17:00:10 +00:00
										 |  |  | typedef struct RTSPActionServerSetup { | 
					
						
							|  |  |  |     uint32_t ipaddr; | 
					
						
							|  |  |  |     char transport_option[512]; | 
					
						
							|  |  |  | } RTSPActionServerSetup; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     int64_t count1, count2; | 
					
						
							| 
									
										
										
										
											2007-02-24 02:39:57 +00:00
										 |  |  |     int64_t time1, time2; | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | } DataRateData; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | /* 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 */ | 
					
						
							| 
									
										
										
										
											2007-02-24 02:39:57 +00:00
										 |  |  |     int64_t timeout; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     uint8_t *buffer_ptr, *buffer_end; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     int http_error; | 
					
						
							| 
									
										
										
										
											2005-10-14 17:29:00 +00:00
										 |  |  |     int post; | 
					
						
							| 
									
										
										
										
											2010-03-03 18:41:50 +00:00
										 |  |  |     int chunked_encoding; | 
					
						
							|  |  |  |     int chunk_size;               /* 0 if it needs to be read */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     struct HTTPContext *next; | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */ | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     int64_t data_count; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* feed input */ | 
					
						
							|  |  |  |     int feed_fd; | 
					
						
							|  |  |  |     /* input format handling */ | 
					
						
							|  |  |  |     AVFormatContext *fmt_in; | 
					
						
							| 
									
										
										
										
											2007-02-24 02:39:57 +00:00
										 |  |  |     int64_t start_time;            /* In milliseconds - this wraps fairly often */ | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     int64_t first_pts;            /* initial pts value */ | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |     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 */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* output format handling */ | 
					
						
							|  |  |  |     struct FFStream *stream; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     /* -1 is invalid stream */ | 
					
						
							|  |  |  |     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */ | 
					
						
							|  |  |  |     int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */ | 
					
						
							|  |  |  |     int switch_pending; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     AVFormatContext fmt_ctx; /* instance of FFStream for one user */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     int last_packet_sent; /* true if last data packet was sent */ | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |     int suppress_log; | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |     DataRateData datarate; | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |     int wmp_client_id; | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |     char protocol[16]; | 
					
						
							|  |  |  |     char method[16]; | 
					
						
							|  |  |  |     char url[128]; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     int buffer_size; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     uint8_t *buffer; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     int is_packetized; /* if true, the stream is packetized */ | 
					
						
							|  |  |  |     int packet_stream_index; /* current stream for output in state machine */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* RTSP state specific */ | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     uint8_t *pb_buffer; /* XXX: use that in all the code */ | 
					
						
							| 
									
										
										
										
											2011-02-20 11:04:12 +01:00
										 |  |  |     AVIOContext *pb; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     int seq; /* RTSP sequence number */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* RTP state specific */ | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     enum RTSPLowerTransport rtp_protocol; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     char session_id[32]; /* session id */ | 
					
						
							|  |  |  |     AVFormatContext *rtp_ctx[MAX_STREAMS]; | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     /* RTP/UDP specific */ | 
					
						
							|  |  |  |     URLContext *rtp_handles[MAX_STREAMS]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* RTP/TCP specific */ | 
					
						
							|  |  |  |     struct HTTPContext *rtsp_c; | 
					
						
							|  |  |  |     uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | } HTTPContext; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* each generated stream is described here */ | 
					
						
							|  |  |  | enum StreamType { | 
					
						
							|  |  |  |     STREAM_TYPE_LIVE, | 
					
						
							|  |  |  |     STREAM_TYPE_STATUS, | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     STREAM_TYPE_REDIRECT, | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  | enum IPAddressAction { | 
					
						
							|  |  |  |     IP_ALLOW = 1, | 
					
						
							|  |  |  |     IP_DENY, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct IPAddressACL { | 
					
						
							|  |  |  |     struct IPAddressACL *next; | 
					
						
							|  |  |  |     enum IPAddressAction action; | 
					
						
							| 
									
										
										
										
											2003-02-23 20:35:47 +00:00
										 |  |  |     /* These are in host order */ | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |     struct in_addr first; | 
					
						
							|  |  |  |     struct in_addr last; | 
					
						
							|  |  |  | } IPAddressACL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | /* description of each stream of the avserver.conf file */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | typedef struct FFStream { | 
					
						
							|  |  |  |     enum StreamType stream_type; | 
					
						
							|  |  |  |     char filename[1024];     /* stream filename */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     struct FFStream *feed;   /* feed we are using (can be null if
 | 
					
						
							|  |  |  |                                 coming from file) */ | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |     AVDictionary *in_opts;   /* input parameters */ | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |     AVInputFormat *ifmt;       /* if non NULL, force input format */ | 
					
						
							| 
									
										
										
										
											2002-05-20 16:33:46 +00:00
										 |  |  |     AVOutputFormat *fmt; | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |     IPAddressACL *acl; | 
					
						
							| 
									
										
										
										
											2010-04-07 20:06:02 +00:00
										 |  |  |     char dynamic_acl[1024]; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     int nb_streams; | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |     int prebuffer;      /* Number of millseconds early to start */ | 
					
						
							| 
									
										
										
										
											2007-02-24 02:39:57 +00:00
										 |  |  |     int64_t max_time;      /* Number of milliseconds to run */ | 
					
						
							| 
									
										
										
										
											2002-05-17 01:53:28 +00:00
										 |  |  |     int send_on_key; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     AVStream *streams[MAX_STREAMS]; | 
					
						
							|  |  |  |     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */ | 
					
						
							|  |  |  |     char feed_filename[1024]; /* file name of the feed storage, or
 | 
					
						
							|  |  |  |                                  input file name for a stream */ | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |     char author[512]; | 
					
						
							|  |  |  |     char title[512]; | 
					
						
							|  |  |  |     char copyright[512]; | 
					
						
							|  |  |  |     char comment[512]; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     pid_t pid;  /* Of ffmpeg process */ | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |     time_t pid_start;  /* Of ffmpeg process */ | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     char **child_argv; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     struct FFStream *next; | 
					
						
							| 
									
										
										
										
											2008-06-21 03:38:49 +00:00
										 |  |  |     unsigned bandwidth; /* bandwidth, in kbits/s */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* RTSP options */ | 
					
						
							|  |  |  |     char *rtsp_option; | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |     /* multicast specific */ | 
					
						
							|  |  |  |     int is_multicast; | 
					
						
							|  |  |  |     struct in_addr multicast_ip; | 
					
						
							|  |  |  |     int multicast_port; /* first port used for multicast */ | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |     int multicast_ttl; | 
					
						
							|  |  |  |     int loop; /* if true, send the stream in loops (only meaningful if file) */ | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* feed specific */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     int feed_opened;     /* true if someone is writing to the feed */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     int is_feed;         /* true if it is a feed */ | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |     int readonly;        /* True if writing is prohibited to the file */ | 
					
						
							| 
									
										
										
										
											2009-03-21 10:28:49 +00:00
										 |  |  |     int truncate;        /* True if feeder connection truncate the feed file */ | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |     int conns_served; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     int64_t bytes_served; | 
					
						
							| 
									
										
										
										
											2005-11-13 03:26:43 +00:00
										 |  |  |     int64_t feed_max_size;      /* maximum storage size, zero means unlimited */ | 
					
						
							| 
									
										
										
										
											2007-12-21 11:50:18 +00:00
										 |  |  |     int64_t feed_write_index;   /* current write position in feed (it wraps around) */ | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     int64_t feed_size;          /* current size of feed */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     struct FFStream *next_feed; | 
					
						
							|  |  |  | } FFStream; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct FeedData { | 
					
						
							|  |  |  |     long long data_count; | 
					
						
							| 
									
										
										
										
											2007-12-21 11:50:18 +00:00
										 |  |  |     float avg_frame_size;   /* frame size averaged over last frames with exponential mean */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | } FeedData; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-25 22:22:19 +00:00
										 |  |  | static struct sockaddr_in my_http_addr; | 
					
						
							|  |  |  | static struct sockaddr_in my_rtsp_addr; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-21 21:15:19 +00:00
										 |  |  | static char logfilename[1024]; | 
					
						
							|  |  |  | static HTTPContext *first_http_ctx; | 
					
						
							|  |  |  | static FFStream *first_feed;   /* contains only feeds */ | 
					
						
							|  |  |  | static FFStream *first_stream; /* contains all streams, including feeds */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | static void new_connection(int server_fd, int is_rtsp); | 
					
						
							|  |  |  | static void close_connection(HTTPContext *c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* HTTP handling */ | 
					
						
							|  |  |  | static int handle_connection(HTTPContext *c); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | static int http_parse_request(HTTPContext *c); | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | static int http_send_data(HTTPContext *c); | 
					
						
							| 
									
										
										
										
											2008-06-19 07:10:44 +00:00
										 |  |  | static void compute_status(HTTPContext *c); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | static int open_input_stream(HTTPContext *c, const char *info); | 
					
						
							|  |  |  | static int http_start_receive_data(HTTPContext *c); | 
					
						
							|  |  |  | static int http_receive_data(HTTPContext *c); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* RTSP handling */ | 
					
						
							|  |  |  | static int rtsp_parse_request(HTTPContext *c); | 
					
						
							|  |  |  | static void rtsp_cmd_describe(HTTPContext *c, const char *url); | 
					
						
							| 
									
										
										
										
											2003-04-04 13:29:58 +00:00
										 |  |  | static void rtsp_cmd_options(HTTPContext *c, const char *url); | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  | 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_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h); | 
					
						
							|  |  |  | static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  | /* SDP handling */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                                    struct in_addr my_ip); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | /* RTP handling */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                                        FFStream *stream, const char *session_id, | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |                                        enum RTSPLowerTransport rtp_protocol); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static int rtp_new_av_stream(HTTPContext *c, | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                              int stream_index, struct sockaddr_in *dest_addr, | 
					
						
							|  |  |  |                              HTTPContext *rtsp_c); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | static const char *my_program_name; | 
					
						
							| 
									
										
										
										
											2002-10-30 02:15:07 +00:00
										 |  |  | static const char *my_program_dir; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | static const char *config_filename = "/etc/avserver.conf"; | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | static int avserver_debug; | 
					
						
							|  |  |  | static int avserver_daemon; | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  | static int no_launch; | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | static int need_to_start_children; | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-03 18:16:34 +00:00
										 |  |  | /* maximum number of simultaneous HTTP connections */ | 
					
						
							|  |  |  | static unsigned int nb_max_http_connections = 2000; | 
					
						
							| 
									
										
										
										
											2008-09-03 20:10:32 +00:00
										 |  |  | static unsigned int nb_max_connections = 5; | 
					
						
							|  |  |  | static unsigned int nb_connections; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-22 00:54:25 +00:00
										 |  |  | static uint64_t max_bandwidth = 1000; | 
					
						
							| 
									
										
										
										
											2008-06-21 03:23:51 +00:00
										 |  |  | static uint64_t current_bandwidth; | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-24 02:39:57 +00:00
										 |  |  | static int64_t cur_time;           // Making this global saves on passing it around everywhere
 | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-20 01:00:53 +00:00
										 |  |  | static AVLFG random_state; | 
					
						
							| 
									
										
										
										
											2007-02-21 13:50:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | static FILE *logfile = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | /* FIXME: make avserver work with IPv6 */ | 
					
						
							| 
									
										
										
										
											2010-03-08 18:43:27 +00:00
										 |  |  | /* resolve host with also IP address parsing */ | 
					
						
							|  |  |  | static int resolve_host(struct in_addr *sin_addr, const char *hostname) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!ff_inet_aton(hostname, sin_addr)) { | 
					
						
							|  |  |  | #if HAVE_GETADDRINFO
 | 
					
						
							|  |  |  |         struct addrinfo *ai, *cur; | 
					
						
							|  |  |  |         struct addrinfo hints; | 
					
						
							|  |  |  |         memset(&hints, 0, sizeof(hints)); | 
					
						
							|  |  |  |         hints.ai_family = AF_INET; | 
					
						
							|  |  |  |         if (getaddrinfo(hostname, NULL, &hints, &ai)) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         /* getaddrinfo returns a linked list of addrinfo structs.
 | 
					
						
							|  |  |  |          * Even if we set ai_family = AF_INET above, make sure | 
					
						
							|  |  |  |          * that the returned one actually is of the correct type. */ | 
					
						
							|  |  |  |         for (cur = ai; cur; cur = cur->ai_next) { | 
					
						
							|  |  |  |             if (cur->ai_family == AF_INET) { | 
					
						
							|  |  |  |                 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr; | 
					
						
							|  |  |  |                 freeaddrinfo(ai); | 
					
						
							|  |  |  |                 return 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         freeaddrinfo(ai); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |         struct hostent *hp; | 
					
						
							|  |  |  |         hp = gethostbyname(hostname); | 
					
						
							|  |  |  |         if (!hp) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-22 01:12:39 +00:00
										 |  |  | static char *ctime1(char *buf2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     time_t ti; | 
					
						
							|  |  |  |     char *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ti = time(NULL); | 
					
						
							|  |  |  |     p = ctime(&ti); | 
					
						
							|  |  |  |     strcpy(buf2, p); | 
					
						
							|  |  |  |     p = buf2 + strlen(p) - 1; | 
					
						
							|  |  |  |     if (*p == '\n') | 
					
						
							|  |  |  |         *p = '\0'; | 
					
						
							|  |  |  |     return buf2; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-22 01:30:41 +00:00
										 |  |  | static void http_vlog(const char *fmt, va_list vargs) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-06-22 01:08:48 +00:00
										 |  |  |     static int print_prefix = 1; | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |     if (logfile) { | 
					
						
							| 
									
										
										
										
											2008-06-22 01:08:48 +00:00
										 |  |  |         if (print_prefix) { | 
					
						
							| 
									
										
										
										
											2008-06-22 01:12:39 +00:00
										 |  |  |             char buf[32]; | 
					
						
							|  |  |  |             ctime1(buf); | 
					
						
							|  |  |  |             fprintf(logfile, "%s ", buf); | 
					
						
							| 
									
										
										
										
											2008-06-22 01:08:48 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         print_prefix = strstr(fmt, "\n") != NULL; | 
					
						
							| 
									
										
										
										
											2008-06-22 01:30:41 +00:00
										 |  |  |         vfprintf(logfile, fmt, vargs); | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |         fflush(logfile); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-06-22 01:30:41 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-16 20:56:32 +01:00
										 |  |  | #ifdef __GNUC__
 | 
					
						
							|  |  |  | __attribute__ ((format (printf, 1, 2))) | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | static void http_log(const char *fmt, ...) | 
					
						
							| 
									
										
										
										
											2008-06-22 01:30:41 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     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; | 
					
						
							| 
									
										
										
										
											2009-03-08 14:33:30 +00:00
										 |  |  |     if (level > av_log_get_level()) | 
					
						
							| 
									
										
										
										
											2008-06-22 01:30:41 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  |     if (print_prefix && avc) | 
					
						
							| 
									
										
										
										
											2008-07-16 03:21:23 +00:00
										 |  |  |         http_log("[%s @ %p]", avc->item_name(ptr), ptr); | 
					
						
							| 
									
										
										
										
											2008-06-22 01:30:41 +00:00
										 |  |  |     print_prefix = strstr(fmt, "\n") != NULL; | 
					
						
							|  |  |  |     http_vlog(fmt, vargs); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  | static void log_connection(HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |     if (c->suppress_log) | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-22 01:13:33 +00:00
										 |  |  |     http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n", | 
					
						
							|  |  |  |              inet_ntoa(c->from_addr.sin_addr), c->method, c->url, | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |              c->protocol, (c->http_error ? c->http_error : 200), c->data_count); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  | static void update_datarate(DataRateData *drd, int64_t count) | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!drd->time1 && !drd->count1) { | 
					
						
							|  |  |  |         drd->time1 = drd->time2 = cur_time; | 
					
						
							|  |  |  |         drd->count1 = drd->count2 = count; | 
					
						
							| 
									
										
										
										
											2007-08-08 18:55:49 +00:00
										 |  |  |     } else if (cur_time - drd->time2 > 5000) { | 
					
						
							| 
									
										
										
										
											2007-08-08 18:56:27 +00:00
										 |  |  |         drd->time1 = drd->time2; | 
					
						
							|  |  |  |         drd->count1 = drd->count2; | 
					
						
							|  |  |  |         drd->time2 = cur_time; | 
					
						
							|  |  |  |         drd->count2 = count; | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* In bytes per second */ | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  | static int compute_datarate(DataRateData *drd, int64_t count) | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     if (cur_time == drd->time1) | 
					
						
							|  |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |     return ((count - drd->count1) * 1000) / (cur_time - drd->time1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-09-12 02:31:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | static void start_children(FFStream *feed) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |     if (no_launch) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     for (; feed; feed = feed->next) { | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |         if (feed->child_argv && !feed->pid) { | 
					
						
							|  |  |  |             feed->pid_start = time(0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             feed->pid = fork(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (feed->pid < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:29:59 +00:00
										 |  |  |                 http_log("Unable to create children\n"); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 exit(1); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (!feed->pid) { | 
					
						
							|  |  |  |                 /* In child */ | 
					
						
							|  |  |  |                 char pathname[1024]; | 
					
						
							|  |  |  |                 char *slash; | 
					
						
							|  |  |  |                 int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-24 21:26:20 +00:00
										 |  |  |                 av_strlcpy(pathname, my_program_name, sizeof(pathname)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 slash = strrchr(pathname, '/'); | 
					
						
							|  |  |  |                 if (!slash) | 
					
						
							|  |  |  |                     slash = pathname; | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     slash++; | 
					
						
							|  |  |  |                 strcpy(slash, "ffmpeg"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-24 22:30:41 +00:00
										 |  |  |                 http_log("Launch commandline: "); | 
					
						
							|  |  |  |                 http_log("%s ", pathname); | 
					
						
							|  |  |  |                 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++) | 
					
						
							|  |  |  |                     http_log("%s ", feed->child_argv[i]); | 
					
						
							|  |  |  |                 http_log("\n"); | 
					
						
							| 
									
										
										
										
											2008-06-24 21:26:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 for (i = 3; i < 256; i++) | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |                     close(i); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |                 if (!avserver_debug) { | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |                     i = open("/dev/null", O_RDWR); | 
					
						
							| 
									
										
										
										
											2008-06-22 00:33:08 +00:00
										 |  |  |                     if (i != -1) { | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |                         dup2(i, 0); | 
					
						
							| 
									
										
										
										
											2008-06-22 00:33:08 +00:00
										 |  |  |                         dup2(i, 1); | 
					
						
							|  |  |  |                         dup2(i, 2); | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |                         close(i); | 
					
						
							| 
									
										
										
										
											2008-06-22 00:33:08 +00:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-30 02:15:07 +00:00
										 |  |  |                 /* This is needed to make relative pathnames work */ | 
					
						
							|  |  |  |                 chdir(my_program_dir); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-12-11 03:16:51 +00:00
										 |  |  |                 signal(SIGPIPE, SIG_DFL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 execvp(pathname, feed->child_argv); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 _exit(1); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | /* open a listening socket */ | 
					
						
							|  |  |  | static int socket_open_listen(struct sockaddr_in *my_addr) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     int server_fd, tmp; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     server_fd = socket(AF_INET,SOCK_STREAM,0); | 
					
						
							|  |  |  |     if (server_fd < 0) { | 
					
						
							|  |  |  |         perror ("socket"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     tmp = 1; | 
					
						
							|  |  |  |     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) { | 
					
						
							| 
									
										
										
										
											2003-01-05 23:09:01 +00:00
										 |  |  |         char bindmsg[32]; | 
					
						
							|  |  |  |         snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port)); | 
					
						
							|  |  |  |         perror (bindmsg); | 
					
						
							| 
									
										
										
										
											2007-02-22 12:17:25 +00:00
										 |  |  |         closesocket(server_fd); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     if (listen (server_fd, 5) < 0) { | 
					
						
							|  |  |  |         perror ("listen"); | 
					
						
							| 
									
										
										
										
											2007-02-22 12:17:25 +00:00
										 |  |  |         closesocket(server_fd); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-04-27 00:41:50 +00:00
										 |  |  |     ff_socket_nonblock(server_fd, 1); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return server_fd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  | /* start all multicast streams */ | 
					
						
							|  |  |  | static void start_multicast(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FFStream *stream; | 
					
						
							|  |  |  |     char session_id[32]; | 
					
						
							|  |  |  |     HTTPContext *rtp_c; | 
					
						
							|  |  |  |     struct sockaddr_in dest_addr; | 
					
						
							|  |  |  |     int default_port, stream_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default_port = 6000; | 
					
						
							|  |  |  |     for(stream = first_stream; stream != NULL; stream = stream->next) { | 
					
						
							|  |  |  |         if (stream->is_multicast) { | 
					
						
							|  |  |  |             /* open the RTP connection */ | 
					
						
							| 
									
										
										
										
											2007-02-21 13:50:32 +00:00
										 |  |  |             snprintf(session_id, sizeof(session_id), "%08x%08x", | 
					
						
							| 
									
										
										
										
											2009-03-20 01:00:53 +00:00
										 |  |  |                      av_lfg_get(&random_state), av_lfg_get(&random_state)); | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             /* choose a port if none given */ | 
					
						
							|  |  |  |             if (stream->multicast_port == 0) { | 
					
						
							|  |  |  |                 stream->multicast_port = default_port; | 
					
						
							|  |  |  |                 default_port += 100; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             dest_addr.sin_family = AF_INET; | 
					
						
							|  |  |  |             dest_addr.sin_addr = stream->multicast_ip; | 
					
						
							|  |  |  |             dest_addr.sin_port = htons(stream->multicast_port); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |             rtp_c = rtp_new_connection(&dest_addr, stream, session_id, | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |                                        RTSP_LOWER_TRANSPORT_UDP_MULTICAST); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (!rtp_c) | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |             if (open_input_stream(rtp_c, "") < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:29:59 +00:00
										 |  |  |                 http_log("Could not open input stream for stream '%s'\n", | 
					
						
							|  |  |  |                          stream->filename); | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* open each RTP stream */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |             for(stream_index = 0; stream_index < stream->nb_streams; | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                 stream_index++) { | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                 dest_addr.sin_port = htons(stream->multicast_port + | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                                            2 * stream_index); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:29:59 +00:00
										 |  |  |                     http_log("Could not open output stream '%s/streamid=%d'\n", | 
					
						
							|  |  |  |                              stream->filename, stream_index); | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  |                     exit(1); | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* change state to send data */ | 
					
						
							|  |  |  |             rtp_c->state = HTTPSTATE_SEND_DATA; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* main loop of the http server */ | 
					
						
							|  |  |  | static int http_server(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |     int server_fd = 0, rtsp_server_fd = 0; | 
					
						
							|  |  |  |     int ret, delay, delay1; | 
					
						
							| 
									
										
										
										
											2008-09-03 18:16:34 +00:00
										 |  |  |     struct pollfd *poll_table, *poll_entry; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     HTTPContext *c, *c_next; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-07 04:16:05 +00:00
										 |  |  |     if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) { | 
					
						
							| 
									
										
										
										
											2008-09-03 18:16:34 +00:00
										 |  |  |         http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |     if (my_http_addr.sin_port) { | 
					
						
							| 
									
										
										
										
											2008-06-22 00:53:28 +00:00
										 |  |  |         server_fd = socket_open_listen(&my_http_addr); | 
					
						
							|  |  |  |         if (server_fd < 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |     if (my_rtsp_addr.sin_port) { | 
					
						
							| 
									
										
										
										
											2008-06-22 00:53:28 +00:00
										 |  |  |         rtsp_server_fd = socket_open_listen(&my_rtsp_addr); | 
					
						
							|  |  |  |         if (rtsp_server_fd < 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!rtsp_server_fd && !server_fd) { | 
					
						
							|  |  |  |         http_log("HTTP and RTSP disabled.\n"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     http_log("AVserver started.\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     start_children(first_feed); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |     start_multicast(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     for(;;) { | 
					
						
							|  |  |  |         poll_entry = poll_table; | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |         if (server_fd) { | 
					
						
							| 
									
										
										
										
											2008-06-22 00:53:28 +00:00
										 |  |  |             poll_entry->fd = server_fd; | 
					
						
							|  |  |  |             poll_entry->events = POLLIN; | 
					
						
							|  |  |  |             poll_entry++; | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (rtsp_server_fd) { | 
					
						
							| 
									
										
										
										
											2008-06-22 00:53:28 +00:00
										 |  |  |             poll_entry->fd = rtsp_server_fd; | 
					
						
							|  |  |  |             poll_entry->events = POLLIN; | 
					
						
							|  |  |  |             poll_entry++; | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         /* wait for events on each HTTP handle */ | 
					
						
							|  |  |  |         c = first_http_ctx; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         delay = 1000; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         while (c != NULL) { | 
					
						
							|  |  |  |             int fd; | 
					
						
							|  |  |  |             fd = c->fd; | 
					
						
							|  |  |  |             switch(c->state) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             case HTTPSTATE_SEND_HEADER: | 
					
						
							|  |  |  |             case RTSPSTATE_SEND_REPLY: | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |             case RTSPSTATE_SEND_PACKET: | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 c->poll_entry = poll_entry; | 
					
						
							|  |  |  |                 poll_entry->fd = fd; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 poll_entry->events = POLLOUT; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 poll_entry++; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case HTTPSTATE_SEND_DATA_HEADER: | 
					
						
							|  |  |  |             case HTTPSTATE_SEND_DATA: | 
					
						
							|  |  |  |             case HTTPSTATE_SEND_DATA_TRAILER: | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 if (!c->is_packetized) { | 
					
						
							|  |  |  |                     /* for TCP, we output as much as we can (may need to put a limit) */ | 
					
						
							|  |  |  |                     c->poll_entry = poll_entry; | 
					
						
							|  |  |  |                     poll_entry->fd = fd; | 
					
						
							|  |  |  |                     poll_entry->events = POLLOUT; | 
					
						
							|  |  |  |                     poll_entry++; | 
					
						
							|  |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |                     /* when avserver is doing the timing, we work by
 | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                        looking at which packet need to be sent every | 
					
						
							|  |  |  |                        10 ms */ | 
					
						
							|  |  |  |                     delay1 = 10; /* one tick wait XXX: 10 ms assumed */ | 
					
						
							|  |  |  |                     if (delay1 < delay) | 
					
						
							|  |  |  |                         delay = delay1; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             case HTTPSTATE_WAIT_REQUEST: | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             case HTTPSTATE_RECEIVE_DATA: | 
					
						
							|  |  |  |             case HTTPSTATE_WAIT_FEED: | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             case RTSPSTATE_WAIT_REQUEST: | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 /* need to catch errors */ | 
					
						
							|  |  |  |                 c->poll_entry = poll_entry; | 
					
						
							|  |  |  |                 poll_entry->fd = fd; | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                 poll_entry->events = POLLIN;/* Maybe this will work */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 poll_entry++; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 c->poll_entry = NULL; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             c = c->next; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* wait for an event on one connection. We poll at least every
 | 
					
						
							|  |  |  |            second to handle timeouts */ | 
					
						
							|  |  |  |         do { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             ret = poll(poll_table, poll_entry - poll_table, delay); | 
					
						
							| 
									
										
										
										
											2011-02-19 19:14:11 +01:00
										 |  |  |             if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) && | 
					
						
							|  |  |  |                 ff_neterrno() != AVERROR(EINTR)) | 
					
						
							| 
									
										
										
										
											2004-07-25 11:59:34 +00:00
										 |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2007-04-10 14:40:03 +00:00
										 |  |  |         } while (ret < 0); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-24 02:39:57 +00:00
										 |  |  |         cur_time = av_gettime() / 1000; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |         if (need_to_start_children) { | 
					
						
							|  |  |  |             need_to_start_children = 0; | 
					
						
							|  |  |  |             start_children(first_feed); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         /* now handle the events */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         for(c = first_http_ctx; c != NULL; c = c_next) { | 
					
						
							|  |  |  |             c_next = c->next; | 
					
						
							|  |  |  |             if (handle_connection(c) < 0) { | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 /* close and free the connection */ | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |                 log_connection(c); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 close_connection(c); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         poll_entry = poll_table; | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |         if (server_fd) { | 
					
						
							| 
									
										
										
										
											2008-06-22 00:53:28 +00:00
										 |  |  |             /* new HTTP connection request ? */ | 
					
						
							|  |  |  |             if (poll_entry->revents & POLLIN) | 
					
						
							|  |  |  |                 new_connection(server_fd, 0); | 
					
						
							|  |  |  |             poll_entry++; | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (rtsp_server_fd) { | 
					
						
							| 
									
										
										
										
											2008-06-22 00:53:28 +00:00
										 |  |  |             /* new RTSP connection request ? */ | 
					
						
							|  |  |  |             if (poll_entry->revents & POLLIN) | 
					
						
							|  |  |  |                 new_connection(rtsp_server_fd, 1); | 
					
						
							| 
									
										
										
										
											2008-06-22 00:52:22 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | /* start waiting for a new HTTP/RTSP request */ | 
					
						
							|  |  |  | static void start_wait_request(HTTPContext *c, int is_rtsp) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |     c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (is_rtsp) { | 
					
						
							|  |  |  |         c->timeout = cur_time + RTSP_REQUEST_TIMEOUT; | 
					
						
							|  |  |  |         c->state = RTSPSTATE_WAIT_REQUEST; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         c->timeout = cur_time + HTTP_REQUEST_TIMEOUT; | 
					
						
							|  |  |  |         c->state = HTTPSTATE_WAIT_REQUEST; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 09:56:25 +00:00
										 |  |  | static void http_send_too_busy_reply(int fd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char buffer[300]; | 
					
						
							|  |  |  |     int len = snprintf(buffer, sizeof(buffer), | 
					
						
							| 
									
										
										
										
											2010-07-08 08:59:53 +00:00
										 |  |  |                        "HTTP/1.0 503 Server too busy\r\n" | 
					
						
							| 
									
										
										
										
											2009-03-21 09:56:25 +00:00
										 |  |  |                        "Content-type: text/html\r\n" | 
					
						
							|  |  |  |                        "\r\n" | 
					
						
							|  |  |  |                        "<html><head><title>Too busy</title></head><body>\r\n" | 
					
						
							|  |  |  |                        "<p>The server is too busy to serve your request at this time.</p>\r\n" | 
					
						
							|  |  |  |                        "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n" | 
					
						
							|  |  |  |                        "</body></html>\r\n", | 
					
						
							|  |  |  |                        nb_connections, nb_max_connections); | 
					
						
							|  |  |  |     send(fd, buffer, len, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | static void new_connection(int server_fd, int is_rtsp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct sockaddr_in from_addr; | 
					
						
							|  |  |  |     int fd, len; | 
					
						
							|  |  |  |     HTTPContext *c = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     len = sizeof(from_addr); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |     fd = accept(server_fd, (struct sockaddr *)&from_addr, | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 &len); | 
					
						
							| 
									
										
										
										
											2008-06-21 03:31:30 +00:00
										 |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         http_log("error during accept %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2008-06-21 03:31:30 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-04-27 00:41:50 +00:00
										 |  |  |     ff_socket_nonblock(fd, 1); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 09:56:25 +00:00
										 |  |  |     if (nb_connections >= nb_max_connections) { | 
					
						
							|  |  |  |         http_send_too_busy_reply(fd); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2009-03-21 09:56:25 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* add a new connection */ | 
					
						
							|  |  |  |     c = av_mallocz(sizeof(HTTPContext)); | 
					
						
							|  |  |  |     if (!c) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->fd = fd; | 
					
						
							|  |  |  |     c->poll_entry = NULL; | 
					
						
							|  |  |  |     c->from_addr = from_addr; | 
					
						
							|  |  |  |     c->buffer_size = IOBUFFER_INIT_SIZE; | 
					
						
							|  |  |  |     c->buffer = av_malloc(c->buffer_size); | 
					
						
							|  |  |  |     if (!c->buffer) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2003-09-27 01:23:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     c->next = first_http_ctx; | 
					
						
							|  |  |  |     first_http_ctx = c; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     nb_connections++; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     start_wait_request(c, is_rtsp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fail: | 
					
						
							|  |  |  |     if (c) { | 
					
						
							|  |  |  |         av_free(c->buffer); | 
					
						
							|  |  |  |         av_free(c); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-02-22 12:17:25 +00:00
										 |  |  |     closesocket(fd); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void close_connection(HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     HTTPContext **cp, *c1; | 
					
						
							|  |  |  |     int i, nb_streams; | 
					
						
							|  |  |  |     AVFormatContext *ctx; | 
					
						
							|  |  |  |     URLContext *h; | 
					
						
							|  |  |  |     AVStream *st; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* remove connection from list */ | 
					
						
							|  |  |  |     cp = &first_http_ctx; | 
					
						
							|  |  |  |     while ((*cp) != NULL) { | 
					
						
							|  |  |  |         c1 = *cp; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         if (c1 == c) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             *cp = c->next; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             cp = &c1->next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     /* remove references, if any (XXX: do it faster) */ | 
					
						
							|  |  |  |     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) { | 
					
						
							|  |  |  |         if (c1->rtsp_c == c) | 
					
						
							|  |  |  |             c1->rtsp_c = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* remove connection associated resources */ | 
					
						
							|  |  |  |     if (c->fd >= 0) | 
					
						
							| 
									
										
										
										
											2007-02-22 12:17:25 +00:00
										 |  |  |         closesocket(c->fd); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     if (c->fmt_in) { | 
					
						
							|  |  |  |         /* close each frame parser */ | 
					
						
							|  |  |  |         for(i=0;i<c->fmt_in->nb_streams;i++) { | 
					
						
							|  |  |  |             st = c->fmt_in->streams[i]; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (st->codec->codec) | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                 avcodec_close(st->codec); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         av_close_input_file(c->fmt_in); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* free RTP output streams if any */ | 
					
						
							|  |  |  |     nb_streams = 0; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |     if (c->stream) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         nb_streams = c->stream->nb_streams; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     for(i=0;i<nb_streams;i++) { | 
					
						
							|  |  |  |         ctx = c->rtp_ctx[i]; | 
					
						
							|  |  |  |         if (ctx) { | 
					
						
							|  |  |  |             av_write_trailer(ctx); | 
					
						
							| 
									
										
										
										
											2011-05-22 12:46:29 +02:00
										 |  |  |             av_dict_free(&ctx->metadata); | 
					
						
							| 
									
										
										
										
											2010-05-24 19:05:22 +00:00
										 |  |  |             av_free(ctx->streams[0]); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             av_free(ctx); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         h = c->rtp_handles[i]; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         if (h) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             url_close(h); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-26 10:30:08 +00:00
										 |  |  |     ctx = &c->fmt_ctx; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-24 17:11:46 +00:00
										 |  |  |     if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) { | 
					
						
							| 
									
										
										
										
											2003-03-04 03:12:32 +00:00
										 |  |  |         if (ctx->oformat) { | 
					
						
							|  |  |  |             /* prepare header */ | 
					
						
							| 
									
										
										
										
											2011-03-17 08:13:34 +01:00
										 |  |  |             if (avio_open_dyn_buf(&ctx->pb) >= 0) { | 
					
						
							| 
									
										
										
										
											2003-03-04 03:12:32 +00:00
										 |  |  |                 av_write_trailer(ctx); | 
					
						
							| 
									
										
										
										
											2008-06-21 06:08:59 +00:00
										 |  |  |                 av_freep(&c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2011-03-17 08:16:07 +01:00
										 |  |  |                 avio_close_dyn_buf(ctx->pb, &c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2003-03-04 03:12:32 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |     for(i=0; i<ctx->nb_streams; i++) | 
					
						
							| 
									
										
										
										
											2007-08-08 19:04:23 +00:00
										 |  |  |         av_free(ctx->streams[i]); | 
					
						
							| 
									
										
										
										
											2003-04-12 02:27:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-14 17:29:00 +00:00
										 |  |  |     if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE) | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |         current_bandwidth -= c->stream->bandwidth; | 
					
						
							| 
									
										
										
										
											2007-02-22 13:27:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* signal that there is no feed if we are the feeder socket */ | 
					
						
							|  |  |  |     if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) { | 
					
						
							|  |  |  |         c->stream->feed_opened = 0; | 
					
						
							|  |  |  |         close(c->feed_fd); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     av_freep(&c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     av_freep(&c->packet_buffer); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     av_free(c->buffer); | 
					
						
							|  |  |  |     av_free(c); | 
					
						
							|  |  |  |     nb_connections--; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_connection(HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int len, ret; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     switch(c->state) { | 
					
						
							|  |  |  |     case HTTPSTATE_WAIT_REQUEST: | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     case RTSPSTATE_WAIT_REQUEST: | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         /* timeout ? */ | 
					
						
							|  |  |  |         if ((c->timeout - cur_time) < 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         if (c->poll_entry->revents & (POLLERR | POLLHUP)) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* no need to read if no events */ | 
					
						
							|  |  |  |         if (!(c->poll_entry->revents & POLLIN)) | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         /* read the data */ | 
					
						
							| 
									
										
										
										
											2003-07-11 22:30:12 +00:00
										 |  |  |     read_loop: | 
					
						
							| 
									
										
										
										
											2007-02-22 12:38:37 +00:00
										 |  |  |         len = recv(c->fd, c->buffer_ptr, 1, 0); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         if (len < 0) { | 
					
						
							| 
									
										
										
										
											2011-02-19 19:14:11 +01:00
										 |  |  |             if (ff_neterrno() != AVERROR(EAGAIN) && | 
					
						
							|  |  |  |                 ff_neterrno() != AVERROR(EINTR)) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |         } else if (len == 0) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2003-06-29 01:25:41 +00:00
										 |  |  |             /* search for end of request. */ | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |             uint8_t *ptr; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             c->buffer_ptr += len; | 
					
						
							|  |  |  |             ptr = c->buffer_ptr; | 
					
						
							|  |  |  |             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) || | 
					
						
							|  |  |  |                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) { | 
					
						
							|  |  |  |                 /* request found : parse it and reply */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 if (c->state == HTTPSTATE_WAIT_REQUEST) { | 
					
						
							|  |  |  |                     ret = http_parse_request(c); | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     ret = rtsp_parse_request(c); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (ret < 0) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                     return -1; | 
					
						
							|  |  |  |             } else if (ptr >= c->buffer_end) { | 
					
						
							|  |  |  |                 /* request too long: cannot do anything */ | 
					
						
							|  |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2003-07-11 22:30:12 +00:00
										 |  |  |             } else goto read_loop; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case HTTPSTATE_SEND_HEADER: | 
					
						
							|  |  |  |         if (c->poll_entry->revents & (POLLERR | POLLHUP)) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         /* no need to write if no events */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         if (!(c->poll_entry->revents & POLLOUT)) | 
					
						
							|  |  |  |             return 0; | 
					
						
							| 
									
										
										
										
											2007-02-22 12:38:37 +00:00
										 |  |  |         len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         if (len < 0) { | 
					
						
							| 
									
										
										
										
											2011-02-19 19:14:11 +01:00
										 |  |  |             if (ff_neterrno() != AVERROR(EAGAIN) && | 
					
						
							|  |  |  |                 ff_neterrno() != AVERROR(EINTR)) { | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 /* error : close connection */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 av_freep(&c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             c->buffer_ptr += len; | 
					
						
							| 
									
										
										
										
											2002-05-20 03:02:09 +00:00
										 |  |  |             if (c->stream) | 
					
						
							|  |  |  |                 c->stream->bytes_served += len; | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |             c->data_count += len; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             if (c->buffer_ptr >= c->buffer_end) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 av_freep(&c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 /* if error, exit */ | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 if (c->http_error) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                     return -1; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 /* all the buffer was sent : synchronize to the incoming stream */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 c->state = HTTPSTATE_SEND_DATA_HEADER; | 
					
						
							|  |  |  |                 c->buffer_ptr = c->buffer_end = c->buffer; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case HTTPSTATE_SEND_DATA: | 
					
						
							|  |  |  |     case HTTPSTATE_SEND_DATA_HEADER: | 
					
						
							|  |  |  |     case HTTPSTATE_SEND_DATA_TRAILER: | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         /* for packetized output, we consider we can always write (the
 | 
					
						
							|  |  |  |            input streams sets the speed). It may be better to verify | 
					
						
							|  |  |  |            that we do not rely too much on the kernel queues */ | 
					
						
							|  |  |  |         if (!c->is_packetized) { | 
					
						
							|  |  |  |             if (c->poll_entry->revents & (POLLERR | POLLHUP)) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             /* no need to read if no events */ | 
					
						
							|  |  |  |             if (!(c->poll_entry->revents & POLLOUT)) | 
					
						
							|  |  |  |                 return 0; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |         if (http_send_data(c) < 0) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2007-02-24 02:16:12 +00:00
										 |  |  |         /* close connection if trailer sent */ | 
					
						
							|  |  |  |         if (c->state == HTTPSTATE_SEND_DATA_TRAILER) | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case HTTPSTATE_RECEIVE_DATA: | 
					
						
							|  |  |  |         /* no need to read if no events */ | 
					
						
							|  |  |  |         if (c->poll_entry->revents & (POLLERR | POLLHUP)) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         if (!(c->poll_entry->revents & POLLIN)) | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         if (http_receive_data(c) < 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case HTTPSTATE_WAIT_FEED: | 
					
						
							|  |  |  |         /* no need to read if no events */ | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |         if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP)) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* nothing to do, we'll be waken up by incoming feed packets */ | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     case RTSPSTATE_SEND_REPLY: | 
					
						
							|  |  |  |         if (c->poll_entry->revents & (POLLERR | POLLHUP)) { | 
					
						
							|  |  |  |             av_freep(&c->pb_buffer); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* no need to write if no events */ | 
					
						
							|  |  |  |         if (!(c->poll_entry->revents & POLLOUT)) | 
					
						
							|  |  |  |             return 0; | 
					
						
							| 
									
										
										
										
											2007-02-22 12:38:37 +00:00
										 |  |  |         len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         if (len < 0) { | 
					
						
							| 
									
										
										
										
											2011-02-19 19:14:11 +01:00
										 |  |  |             if (ff_neterrno() != AVERROR(EAGAIN) && | 
					
						
							|  |  |  |                 ff_neterrno() != AVERROR(EINTR)) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 /* error : close connection */ | 
					
						
							|  |  |  |                 av_freep(&c->pb_buffer); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             c->buffer_ptr += len; | 
					
						
							|  |  |  |             c->data_count += len; | 
					
						
							|  |  |  |             if (c->buffer_ptr >= c->buffer_end) { | 
					
						
							|  |  |  |                 /* all the buffer was sent : wait for a new request */ | 
					
						
							|  |  |  |                 av_freep(&c->pb_buffer); | 
					
						
							|  |  |  |                 start_wait_request(c, 1); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     case RTSPSTATE_SEND_PACKET: | 
					
						
							|  |  |  |         if (c->poll_entry->revents & (POLLERR | POLLHUP)) { | 
					
						
							|  |  |  |             av_freep(&c->packet_buffer); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* no need to write if no events */ | 
					
						
							|  |  |  |         if (!(c->poll_entry->revents & POLLOUT)) | 
					
						
							|  |  |  |             return 0; | 
					
						
							| 
									
										
										
										
											2007-02-22 12:38:37 +00:00
										 |  |  |         len = send(c->fd, c->packet_buffer_ptr, | 
					
						
							|  |  |  |                     c->packet_buffer_end - c->packet_buffer_ptr, 0); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         if (len < 0) { | 
					
						
							| 
									
										
										
										
											2011-02-19 19:14:11 +01:00
										 |  |  |             if (ff_neterrno() != AVERROR(EAGAIN) && | 
					
						
							|  |  |  |                 ff_neterrno() != AVERROR(EINTR)) { | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                 /* error : close connection */ | 
					
						
							|  |  |  |                 av_freep(&c->packet_buffer); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             c->packet_buffer_ptr += len; | 
					
						
							|  |  |  |             if (c->packet_buffer_ptr >= c->packet_buffer_end) { | 
					
						
							|  |  |  |                 /* all the buffer was sent : wait for a new request */ | 
					
						
							|  |  |  |                 av_freep(&c->packet_buffer); | 
					
						
							|  |  |  |                 c->state = RTSPSTATE_WAIT_REQUEST; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     case HTTPSTATE_READY: | 
					
						
							|  |  |  |         /* nothing to do */ | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     default: | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | static int extract_rates(char *rates, int ratelen, const char *request) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (p = request; *p && *p != '\r' && *p != '\n'; ) { | 
					
						
							|  |  |  |         if (strncasecmp(p, "Pragma:", 7) == 0) { | 
					
						
							|  |  |  |             const char *q = p + 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             while (*q && *q != '\n' && isspace(*q)) | 
					
						
							|  |  |  |                 q++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (strncasecmp(q, "stream-switch-entry=", 20) == 0) { | 
					
						
							|  |  |  |                 int stream_no; | 
					
						
							|  |  |  |                 int rate_no; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 q += 20; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 memset(rates, 0xff, ratelen); | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 while (1) { | 
					
						
							|  |  |  |                     while (*q && *q != '\n' && *q != ':') | 
					
						
							|  |  |  |                         q++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |                         break; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |                     stream_no--; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     if (stream_no < ratelen && stream_no >= 0) | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |                         rates[stream_no] = rate_no; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     while (*q && *q != '\n' && !isspace(*q)) | 
					
						
							|  |  |  |                         q++; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return 1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         p = strchr(p, '\n'); | 
					
						
							|  |  |  |         if (!p) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate) | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     int best_bitrate = 100000000; | 
					
						
							|  |  |  |     int best = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < feed->nb_streams; i++) { | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |         AVCodecContext *feed_codec = feed->streams[i]->codec; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (feed_codec->codec_id != codec->codec_id || | 
					
						
							|  |  |  |             feed_codec->sample_rate != codec->sample_rate || | 
					
						
							|  |  |  |             feed_codec->width != codec->width || | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             feed_codec->height != codec->height) | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Potential stream */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         /* We want the fastest stream less than bit_rate, or the slowest
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |          * faster than bit_rate | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (feed_codec->bit_rate <= bit_rate) { | 
					
						
							|  |  |  |             if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) { | 
					
						
							|  |  |  |                 best_bitrate = feed_codec->bit_rate; | 
					
						
							|  |  |  |                 best = i; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             if (feed_codec->bit_rate < best_bitrate) { | 
					
						
							|  |  |  |                 best_bitrate = feed_codec->bit_rate; | 
					
						
							|  |  |  |                 best = i; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return best; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int modify_current_stream(HTTPContext *c, char *rates) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     FFStream *req = c->stream; | 
					
						
							|  |  |  |     int action_required = 0; | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-03 20:00:49 +00:00
										 |  |  |     /* Not much we can do for a feed */ | 
					
						
							|  |  |  |     if (!req->feed) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |     for (i = 0; i < req->nb_streams; i++) { | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |         AVCodecContext *codec = req->streams[i]->codec; | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         switch(rates[i]) { | 
					
						
							|  |  |  |             case 0: | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 c->switch_feed_streams[i] = req->feed_streams[i]; | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             case 1: | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2); | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             case 2: | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 /* Wants off or slow */ | 
					
						
							|  |  |  |                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4); | 
					
						
							|  |  |  | #ifdef WANTS_OFF
 | 
					
						
							|  |  |  |                 /* This doesn't work well when it turns off the only stream! */ | 
					
						
							|  |  |  |                 c->switch_feed_streams[i] = -2; | 
					
						
							|  |  |  |                 c->feed_streams[i] = -2; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i]) | 
					
						
							|  |  |  |             action_required = 1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     return action_required; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | /* XXX: factorize in utils.c ? */ | 
					
						
							|  |  |  | /* XXX: take care with different space meaning */ | 
					
						
							|  |  |  | static void skip_spaces(const char **pp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  |     p = *pp; | 
					
						
							|  |  |  |     while (*p == ' ' || *p == '\t') | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     *pp = p; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void get_word(char *buf, int buf_size, const char **pp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  |     char *q; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     p = *pp; | 
					
						
							|  |  |  |     skip_spaces(&p); | 
					
						
							|  |  |  |     q = buf; | 
					
						
							|  |  |  |     while (!isspace(*p) && *p != '\0') { | 
					
						
							|  |  |  |         if ((q - buf) < buf_size - 1) | 
					
						
							|  |  |  |             *q++ = *p; | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (buf_size > 0) | 
					
						
							|  |  |  |         *q = '\0'; | 
					
						
							|  |  |  |     *pp = p; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-10 19:08:03 +00:00
										 |  |  | static void get_arg(char *buf, int buf_size, const char **pp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  |     char *q; | 
					
						
							|  |  |  |     int quote; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     p = *pp; | 
					
						
							|  |  |  |     while (isspace(*p)) p++; | 
					
						
							|  |  |  |     q = buf; | 
					
						
							|  |  |  |     quote = 0; | 
					
						
							|  |  |  |     if (*p == '\"' || *p == '\'') | 
					
						
							|  |  |  |         quote = *p++; | 
					
						
							|  |  |  |     for(;;) { | 
					
						
							|  |  |  |         if (quote) { | 
					
						
							|  |  |  |             if (*p == quote) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             if (isspace(*p)) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (*p == '\0') | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         if ((q - buf) < buf_size - 1) | 
					
						
							|  |  |  |             *q++ = *p; | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     *q = '\0'; | 
					
						
							|  |  |  |     if (quote && *p == quote) | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     *pp = p; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-07 20:06:02 +00:00
										 |  |  | static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl, | 
					
						
							|  |  |  |                          const char *p, const char *filename, int line_num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char arg[1024]; | 
					
						
							|  |  |  |     IPAddressACL acl; | 
					
						
							|  |  |  |     int errors = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |     if (strcasecmp(arg, "allow") == 0) | 
					
						
							|  |  |  |         acl.action = IP_ALLOW; | 
					
						
							|  |  |  |     else if (strcasecmp(arg, "deny") == 0) | 
					
						
							|  |  |  |         acl.action = IP_DENY; | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n", | 
					
						
							|  |  |  |                 filename, line_num, arg); | 
					
						
							|  |  |  |         errors++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (resolve_host(&acl.first, arg) != 0) { | 
					
						
							|  |  |  |         fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n", | 
					
						
							|  |  |  |                 filename, line_num, arg); | 
					
						
							|  |  |  |         errors++; | 
					
						
							|  |  |  |     } else | 
					
						
							|  |  |  |         acl.last = acl.first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (arg[0]) { | 
					
						
							|  |  |  |         if (resolve_host(&acl.last, arg) != 0) { | 
					
						
							|  |  |  |             fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n", | 
					
						
							|  |  |  |                     filename, line_num, arg); | 
					
						
							|  |  |  |             errors++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!errors) { | 
					
						
							|  |  |  |         IPAddressACL *nacl = av_mallocz(sizeof(*nacl)); | 
					
						
							|  |  |  |         IPAddressACL **naclp = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         acl.next = 0; | 
					
						
							|  |  |  |         *nacl = acl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (stream) | 
					
						
							|  |  |  |             naclp = &stream->acl; | 
					
						
							|  |  |  |         else if (feed) | 
					
						
							|  |  |  |             naclp = &feed->acl; | 
					
						
							|  |  |  |         else if (ext_acl) | 
					
						
							|  |  |  |             naclp = &ext_acl; | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n", | 
					
						
							|  |  |  |                     filename, line_num); | 
					
						
							|  |  |  |             errors++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (naclp) { | 
					
						
							|  |  |  |             while (*naclp) | 
					
						
							|  |  |  |                 naclp = &(*naclp)->next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             *naclp = nacl; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FILE* f; | 
					
						
							|  |  |  |     char line[1024]; | 
					
						
							|  |  |  |     char  cmd[1024]; | 
					
						
							|  |  |  |     IPAddressACL *acl = NULL; | 
					
						
							|  |  |  |     int line_num = 0; | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     f = fopen(stream->dynamic_acl, "r"); | 
					
						
							|  |  |  |     if (!f) { | 
					
						
							|  |  |  |         perror(stream->dynamic_acl); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     acl = av_mallocz(sizeof(IPAddressACL)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Build ACL */ | 
					
						
							|  |  |  |     for(;;) { | 
					
						
							|  |  |  |         if (fgets(line, sizeof(line), f) == NULL) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         line_num++; | 
					
						
							|  |  |  |         p = line; | 
					
						
							|  |  |  |         while (isspace(*p)) | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  |         if (*p == '\0' || *p == '#') | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         get_arg(cmd, sizeof(cmd), &p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!strcasecmp(cmd, "ACL")) | 
					
						
							|  |  |  |             parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     fclose(f); | 
					
						
							|  |  |  |     return acl; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void free_acl_list(IPAddressACL *in_acl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     IPAddressACL *pacl,*pacl2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pacl = in_acl; | 
					
						
							|  |  |  |     while(pacl) { | 
					
						
							|  |  |  |         pacl2 = pacl; | 
					
						
							|  |  |  |         pacl = pacl->next; | 
					
						
							|  |  |  |         av_freep(pacl2); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c) | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     enum IPAddressAction last_action = IP_DENY; | 
					
						
							|  |  |  |     IPAddressACL *acl; | 
					
						
							|  |  |  |     struct in_addr *src = &c->from_addr.sin_addr; | 
					
						
							| 
									
										
										
										
											2007-04-25 22:23:38 +00:00
										 |  |  |     unsigned long src_addr = src->s_addr; | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-07 20:06:02 +00:00
										 |  |  |     for (acl = in_acl; acl; acl = acl->next) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr) | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |             return (acl->action == IP_ALLOW) ? 1 : 0; | 
					
						
							|  |  |  |         last_action = acl->action; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Nothing matched, so return not the last action */ | 
					
						
							|  |  |  |     return (last_action == IP_DENY) ? 1 : 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-07 20:06:02 +00:00
										 |  |  | static int validate_acl(FFStream *stream, HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int ret = 0; | 
					
						
							|  |  |  |     IPAddressACL *acl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* if stream->acl is null validate_acl_list will return 1 */ | 
					
						
							|  |  |  |     ret = validate_acl_list(stream->acl, c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (stream->dynamic_acl[0]) { | 
					
						
							|  |  |  |         acl = parse_dynamic_acl(stream, c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ret = validate_acl_list(acl, c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         free_acl_list(acl); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  | /* compute the real filename of a file by matching it without its
 | 
					
						
							|  |  |  |    extensions to all the stream filenames */ | 
					
						
							|  |  |  | static void compute_real_filename(char *filename, int max_size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char file1[1024]; | 
					
						
							|  |  |  |     char file2[1024]; | 
					
						
							|  |  |  |     char *p; | 
					
						
							|  |  |  |     FFStream *stream; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* compute filename by matching without the file extensions */ | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     av_strlcpy(file1, filename, sizeof(file1)); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |     p = strrchr(file1, '.'); | 
					
						
							|  |  |  |     if (p) | 
					
						
							|  |  |  |         *p = '\0'; | 
					
						
							|  |  |  |     for(stream = first_stream; stream != NULL; stream = stream->next) { | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |         av_strlcpy(file2, stream->filename, sizeof(file2)); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |         p = strrchr(file2, '.'); | 
					
						
							|  |  |  |         if (p) | 
					
						
							|  |  |  |             *p = '\0'; | 
					
						
							|  |  |  |         if (!strcmp(file1, file2)) { | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |             av_strlcpy(filename, stream->filename, max_size); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum RedirType { | 
					
						
							|  |  |  |     REDIR_NONE, | 
					
						
							|  |  |  |     REDIR_ASX, | 
					
						
							|  |  |  |     REDIR_RAM, | 
					
						
							|  |  |  |     REDIR_ASF, | 
					
						
							|  |  |  |     REDIR_RTSP, | 
					
						
							|  |  |  |     REDIR_SDP, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | /* parse http request and prepare header */ | 
					
						
							|  |  |  | static int http_parse_request(HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char *p; | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |     enum RedirType redir_type; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     char cmd[32]; | 
					
						
							| 
									
										
										
										
											2007-02-24 03:17:59 +00:00
										 |  |  |     char info[1024], filename[1024]; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     char url[1024], *q; | 
					
						
							|  |  |  |     char protocol[32]; | 
					
						
							|  |  |  |     char msg[1024]; | 
					
						
							|  |  |  |     const char *mime_type; | 
					
						
							|  |  |  |     FFStream *stream; | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |     char ratebuf[32]; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     char *useragent = 0; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     p = c->buffer; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     get_word(cmd, sizeof(cmd), (const char **)&p); | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     av_strlcpy(c->method, cmd, sizeof(c->method)); | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     if (!strcmp(cmd, "GET")) | 
					
						
							| 
									
										
										
										
											2005-10-14 17:29:00 +00:00
										 |  |  |         c->post = 0; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     else if (!strcmp(cmd, "POST")) | 
					
						
							| 
									
										
										
										
											2005-10-14 17:29:00 +00:00
										 |  |  |         c->post = 1; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     else | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     get_word(url, sizeof(url), (const char **)&p); | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     av_strlcpy(c->url, url, sizeof(c->url)); | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     get_word(protocol, sizeof(protocol), (const char **)&p); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1")) | 
					
						
							|  |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     av_strlcpy(c->protocol, protocol, sizeof(c->protocol)); | 
					
						
							| 
									
										
										
										
											2005-11-13 03:12:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     if (avserver_debug) | 
					
						
							| 
									
										
										
										
											2009-03-20 01:05:51 +00:00
										 |  |  |         http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* find the filename and the optional info string in the request */ | 
					
						
							| 
									
										
										
										
											2007-02-24 03:17:59 +00:00
										 |  |  |     p = strchr(url, '?'); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     if (p) { | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |         av_strlcpy(info, p, sizeof(info)); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         *p = '\0'; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     } else | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         info[0] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1); | 
					
						
							| 
									
										
										
										
											2007-02-24 03:17:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { | 
					
						
							|  |  |  |         if (strncasecmp(p, "User-Agent:", 11) == 0) { | 
					
						
							|  |  |  |             useragent = p + 11; | 
					
						
							|  |  |  |             if (*useragent && *useragent != '\n' && isspace(*useragent)) | 
					
						
							|  |  |  |                 useragent++; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         p = strchr(p, '\n'); | 
					
						
							|  |  |  |         if (!p) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |     redir_type = REDIR_NONE; | 
					
						
							| 
									
										
										
										
											2010-01-01 23:56:09 +00:00
										 |  |  |     if (av_match_ext(filename, "asx")) { | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |         redir_type = REDIR_ASX; | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |         filename[strlen(filename)-1] = 'f'; | 
					
						
							| 
									
										
										
										
											2010-01-01 23:56:09 +00:00
										 |  |  |     } else if (av_match_ext(filename, "asf") && | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) { | 
					
						
							|  |  |  |         /* if this isn't WMP or lookalike, return the redirector file */ | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |         redir_type = REDIR_ASF; | 
					
						
							| 
									
										
										
										
											2010-01-01 23:56:09 +00:00
										 |  |  |     } else if (av_match_ext(filename, "rpm,ram")) { | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |         redir_type = REDIR_RAM; | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         strcpy(filename + strlen(filename)-2, "m"); | 
					
						
							| 
									
										
										
										
											2010-01-01 23:56:09 +00:00
										 |  |  |     } else if (av_match_ext(filename, "rtsp")) { | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |         redir_type = REDIR_RTSP; | 
					
						
							| 
									
										
										
										
											2007-02-24 03:17:59 +00:00
										 |  |  |         compute_real_filename(filename, sizeof(filename) - 1); | 
					
						
							| 
									
										
										
										
											2010-01-01 23:56:09 +00:00
										 |  |  |     } else if (av_match_ext(filename, "sdp")) { | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |         redir_type = REDIR_SDP; | 
					
						
							| 
									
										
										
										
											2007-02-24 03:17:59 +00:00
										 |  |  |         compute_real_filename(filename, sizeof(filename) - 1); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-24 03:17:59 +00:00
										 |  |  |     // "redirect" / request to index.html
 | 
					
						
							|  |  |  |     if (!strlen(filename)) | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |         av_strlcpy(filename, "index.html", sizeof(filename) - 1); | 
					
						
							| 
									
										
										
										
											2007-02-24 03:17:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     stream = first_stream; | 
					
						
							|  |  |  |     while (stream != NULL) { | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |         if (!strcmp(stream->filename, filename) && validate_acl(stream, c)) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             break; | 
					
						
							|  |  |  |         stream = stream->next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (stream == NULL) { | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |         snprintf(msg, sizeof(msg), "File '%s' not found", url); | 
					
						
							| 
									
										
										
										
											2009-03-20 01:05:51 +00:00
										 |  |  |         http_log("File '%s' not found\n", url); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         goto send_error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     c->stream = stream; | 
					
						
							|  |  |  |     memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams)); | 
					
						
							|  |  |  |     memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (stream->stream_type == STREAM_TYPE_REDIRECT) { | 
					
						
							|  |  |  |         c->http_error = 301; | 
					
						
							|  |  |  |         q = c->buffer; | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |         q += snprintf(q, c->buffer_size, | 
					
						
							|  |  |  |                       "HTTP/1.0 301 Moved\r\n" | 
					
						
							|  |  |  |                       "Location: %s\r\n" | 
					
						
							|  |  |  |                       "Content-type: text/html\r\n" | 
					
						
							|  |  |  |                       "\r\n" | 
					
						
							|  |  |  |                       "<html><head><title>Moved</title></head><body>\r\n" | 
					
						
							|  |  |  |                       "You should be <a href=\"%s\">redirected</a>.\r\n" | 
					
						
							|  |  |  |                       "</body></html>\r\n", stream->feed_filename, stream->feed_filename); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         /* prepare output buffer */ | 
					
						
							|  |  |  |         c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |         c->buffer_end = q; | 
					
						
							|  |  |  |         c->state = HTTPSTATE_SEND_HEADER; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |     /* If this is WMP, get the rate information */ | 
					
						
							|  |  |  |     if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) { | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         if (modify_current_stream(c, ratebuf)) { | 
					
						
							| 
									
										
										
										
											2008-10-21 21:40:24 +00:00
										 |  |  |             for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) { | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 if (c->switch_feed_streams[i] >= 0) | 
					
						
							| 
									
										
										
										
											2011-01-23 08:53:40 +01:00
										 |  |  |                     c->switch_feed_streams[i] = -1; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-22 02:06:55 +00:00
										 |  |  |     if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE) | 
					
						
							|  |  |  |         current_bandwidth += stream->bandwidth; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 09:29:25 +00:00
										 |  |  |     /* If already streaming this feed, do not let start another feeder. */ | 
					
						
							| 
									
										
										
										
											2007-03-06 13:29:04 +00:00
										 |  |  |     if (stream->feed_opened) { | 
					
						
							|  |  |  |         snprintf(msg, sizeof(msg), "This feed is already being received."); | 
					
						
							| 
									
										
										
										
											2009-03-20 01:05:51 +00:00
										 |  |  |         http_log("Feed '%s' already being received\n", stream->feed_filename); | 
					
						
							| 
									
										
										
										
											2007-03-06 13:29:04 +00:00
										 |  |  |         goto send_error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-14 17:29:00 +00:00
										 |  |  |     if (c->post == 0 && max_bandwidth < current_bandwidth) { | 
					
						
							| 
									
										
										
										
											2010-07-08 09:21:24 +00:00
										 |  |  |         c->http_error = 503; | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         q = c->buffer; | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |         q += snprintf(q, c->buffer_size, | 
					
						
							| 
									
										
										
										
											2010-07-08 09:21:24 +00:00
										 |  |  |                       "HTTP/1.0 503 Server too busy\r\n" | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                       "Content-type: text/html\r\n" | 
					
						
							|  |  |  |                       "\r\n" | 
					
						
							|  |  |  |                       "<html><head><title>Too busy</title></head><body>\r\n" | 
					
						
							|  |  |  |                       "<p>The server is too busy to serve your request at this time.</p>\r\n" | 
					
						
							| 
									
										
										
										
											2008-10-01 20:45:06 +00:00
										 |  |  |                       "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, " | 
					
						
							|  |  |  |                       "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n" | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                       "</body></html>\r\n", current_bandwidth, max_bandwidth); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         /* prepare output buffer */ | 
					
						
							|  |  |  |         c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |         c->buffer_end = q; | 
					
						
							|  |  |  |         c->state = HTTPSTATE_SEND_HEADER; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |     if (redir_type != REDIR_NONE) { | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |         char *hostinfo = 0; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |         for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { | 
					
						
							|  |  |  |             if (strncasecmp(p, "Host:", 5) == 0) { | 
					
						
							|  |  |  |                 hostinfo = p + 5; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             p = strchr(p, '\n'); | 
					
						
							|  |  |  |             if (!p) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (hostinfo) { | 
					
						
							|  |  |  |             char *eoh; | 
					
						
							|  |  |  |             char hostbuf[260]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             while (isspace(*hostinfo)) | 
					
						
							|  |  |  |                 hostinfo++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             eoh = strchr(hostinfo, '\n'); | 
					
						
							|  |  |  |             if (eoh) { | 
					
						
							|  |  |  |                 if (eoh[-1] == '\r') | 
					
						
							|  |  |  |                     eoh--; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (eoh - hostinfo < sizeof(hostbuf) - 1) { | 
					
						
							|  |  |  |                     memcpy(hostbuf, hostinfo, eoh - hostinfo); | 
					
						
							|  |  |  |                     hostbuf[eoh - hostinfo] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     c->http_error = 200; | 
					
						
							|  |  |  |                     q = c->buffer; | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                     switch(redir_type) { | 
					
						
							|  |  |  |                     case REDIR_ASX: | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                         q += snprintf(q, c->buffer_size, | 
					
						
							|  |  |  |                                       "HTTP/1.0 200 ASX Follows\r\n" | 
					
						
							|  |  |  |                                       "Content-type: video/x-ms-asf\r\n" | 
					
						
							|  |  |  |                                       "\r\n" | 
					
						
							|  |  |  |                                       "<ASX Version=\"3\">\r\n" | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |                                       //"<!-- Autogenerated by avserver -->\r\n"
 | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                                       "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n" | 
					
						
							|  |  |  |                                       "</ASX>\r\n", hostbuf, filename, info); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                         break; | 
					
						
							|  |  |  |                     case REDIR_RAM: | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                         q += snprintf(q, c->buffer_size, | 
					
						
							|  |  |  |                                       "HTTP/1.0 200 RAM Follows\r\n" | 
					
						
							|  |  |  |                                       "Content-type: audio/x-pn-realaudio\r\n" | 
					
						
							|  |  |  |                                       "\r\n" | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |                                       "# Autogenerated by avserver\r\n" | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                                       "http://%s/%s%s\r\n", hostbuf, filename, info); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                         break; | 
					
						
							|  |  |  |                     case REDIR_ASF: | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                         q += snprintf(q, c->buffer_size, | 
					
						
							|  |  |  |                                       "HTTP/1.0 200 ASF Redirect follows\r\n" | 
					
						
							|  |  |  |                                       "Content-type: video/x-ms-asf\r\n" | 
					
						
							|  |  |  |                                       "\r\n" | 
					
						
							|  |  |  |                                       "[Reference]\r\n" | 
					
						
							|  |  |  |                                       "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                         break; | 
					
						
							|  |  |  |                     case REDIR_RTSP: | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             char hostname[256], *p; | 
					
						
							|  |  |  |                             /* extract only hostname */ | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |                             av_strlcpy(hostname, hostbuf, sizeof(hostname)); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                             p = strrchr(hostname, ':'); | 
					
						
							|  |  |  |                             if (p) | 
					
						
							|  |  |  |                                 *p = '\0'; | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                             q += snprintf(q, c->buffer_size, | 
					
						
							|  |  |  |                                           "HTTP/1.0 200 RTSP Redirect follows\r\n" | 
					
						
							|  |  |  |                                           /* XXX: incorrect mime type ? */ | 
					
						
							|  |  |  |                                           "Content-type: application/x-rtsp\r\n" | 
					
						
							|  |  |  |                                           "\r\n" | 
					
						
							|  |  |  |                                           "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                         } | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case REDIR_SDP: | 
					
						
							|  |  |  |                         { | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |                             uint8_t *sdp_data; | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                             int sdp_data_size, len; | 
					
						
							|  |  |  |                             struct sockaddr_in my_addr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |                             q += snprintf(q, c->buffer_size, | 
					
						
							|  |  |  |                                           "HTTP/1.0 200 OK\r\n" | 
					
						
							|  |  |  |                                           "Content-type: application/sdp\r\n" | 
					
						
							|  |  |  |                                           "\r\n"); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                             len = sizeof(my_addr); | 
					
						
							|  |  |  |                             getsockname(c->fd, (struct sockaddr *)&my_addr, &len); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                             /* XXX: should use a dynamic buffer */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                             sdp_data_size = prepare_sdp_description(stream, | 
					
						
							|  |  |  |                                                                     &sdp_data, | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                                                                     my_addr.sin_addr); | 
					
						
							|  |  |  |                             if (sdp_data_size > 0) { | 
					
						
							|  |  |  |                                 memcpy(q, sdp_data, sdp_data_size); | 
					
						
							|  |  |  |                                 q += sdp_data_size; | 
					
						
							|  |  |  |                                 *q = '\0'; | 
					
						
							|  |  |  |                                 av_free(sdp_data); | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     default: | 
					
						
							| 
									
										
										
										
											2007-07-02 07:43:23 +00:00
										 |  |  |                         abort(); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                         break; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     /* prepare output buffer */ | 
					
						
							|  |  |  |                     c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |                     c->buffer_end = q; | 
					
						
							|  |  |  |                     c->state = HTTPSTATE_SEND_HEADER; | 
					
						
							|  |  |  |                     return 0; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |         snprintf(msg, sizeof(msg), "ASX/RAM file not handled"); | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |         goto send_error; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |     stream->conns_served++; | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* XXX: add there authenticate and IP match */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-14 17:29:00 +00:00
										 |  |  |     if (c->post) { | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         /* if post, it means a feed is being sent */ | 
					
						
							|  |  |  |         if (!stream->is_feed) { | 
					
						
							| 
									
										
										
										
											2008-07-24 21:12:37 +00:00
										 |  |  |             /* However it might be a status report from WMP! Let us log the
 | 
					
						
							|  |  |  |              * data as it might come in handy one day. */ | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |             char *logline = 0; | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |             int client_id = 0; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |             for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) { | 
					
						
							|  |  |  |                 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) { | 
					
						
							|  |  |  |                     logline = p; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 if (strncasecmp(p, "Pragma: client-id=", 18) == 0) | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |                     client_id = strtol(p + 18, 0, 10); | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |                 p = strchr(p, '\n'); | 
					
						
							|  |  |  |                 if (!p) | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 p++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (logline) { | 
					
						
							|  |  |  |                 char *eol = strchr(logline, '\n'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 logline += 17; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (eol) { | 
					
						
							|  |  |  |                     if (eol[-1] == '\r') | 
					
						
							|  |  |  |                         eol--; | 
					
						
							| 
									
										
										
										
											2004-03-24 23:32:48 +00:00
										 |  |  |                     http_log("%.*s\n", (int) (eol - logline), logline); | 
					
						
							| 
									
										
										
										
											2002-05-10 02:20:27 +00:00
										 |  |  |                     c->suppress_log = 1; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-02 22:45:15 +02:00
										 |  |  | #ifdef DEBUG
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             http_log("\nGot request:\n%s\n", c->buffer); | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) { | 
					
						
							|  |  |  |                 HTTPContext *wmpc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 /* Now we have to find the client_id */ | 
					
						
							|  |  |  |                 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) { | 
					
						
							|  |  |  |                     if (wmpc->wmp_client_id == client_id) | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:23:40 +00:00
										 |  |  |                 if (wmpc && modify_current_stream(wmpc, ratebuf)) | 
					
						
							|  |  |  |                     wmpc->switch_pending = 1; | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |             snprintf(msg, sizeof(msg), "POST command not handled"); | 
					
						
							| 
									
										
										
										
											2003-03-04 02:56:51 +00:00
										 |  |  |             c->stream = 0; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             goto send_error; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (http_start_receive_data(c) < 0) { | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |             snprintf(msg, sizeof(msg), "could not open feed"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             goto send_error; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         c->http_error = 0; | 
					
						
							|  |  |  |         c->state = HTTPSTATE_RECEIVE_DATA; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-02 22:45:15 +02:00
										 |  |  | #ifdef DEBUG
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         http_log("\nGot request:\n%s\n", c->buffer); | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     if (c->stream->stream_type == STREAM_TYPE_STATUS) | 
					
						
							| 
									
										
										
										
											2008-06-19 07:10:44 +00:00
										 |  |  |         goto send_status; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* open input stream */ | 
					
						
							|  |  |  |     if (open_input_stream(c, info) < 0) { | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |         snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         goto send_error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* prepare http header */ | 
					
						
							|  |  |  |     q = c->buffer; | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     mime_type = c->stream->fmt->mime_type; | 
					
						
							|  |  |  |     if (!mime_type) | 
					
						
							| 
									
										
										
										
											2007-03-31 14:39:04 +00:00
										 |  |  |         mime_type = "application/x-octet-stream"; | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* for asf, we need extra headers */ | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |     if (!strcmp(c->stream->fmt->name,"asf_stream")) { | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  |         /* Need to allocate a client id */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-20 01:00:53 +00:00
										 |  |  |         c->wmp_client_id = av_lfg_get(&random_state); | 
					
						
							| 
									
										
										
										
											2002-05-26 03:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |         q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type); | 
					
						
							|  |  |  |     q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n"); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* prepare output buffer */ | 
					
						
							|  |  |  |     c->http_error = 0; | 
					
						
							|  |  |  |     c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |     c->buffer_end = q; | 
					
						
							|  |  |  |     c->state = HTTPSTATE_SEND_HEADER; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |  send_error: | 
					
						
							|  |  |  |     c->http_error = 404; | 
					
						
							|  |  |  |     q = c->buffer; | 
					
						
							| 
									
										
										
										
											2008-09-07 04:56:44 +00:00
										 |  |  |     q += snprintf(q, c->buffer_size, | 
					
						
							|  |  |  |                   "HTTP/1.0 404 Not Found\r\n" | 
					
						
							|  |  |  |                   "Content-type: text/html\r\n" | 
					
						
							|  |  |  |                   "\r\n" | 
					
						
							| 
									
										
										
										
											2009-07-19 10:44:36 +00:00
										 |  |  |                   "<html>\n" | 
					
						
							|  |  |  |                   "<head><title>404 Not Found</title></head>\n" | 
					
						
							|  |  |  |                   "<body>%s</body>\n" | 
					
						
							|  |  |  |                   "</html>\n", msg); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* prepare output buffer */ | 
					
						
							|  |  |  |     c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |     c->buffer_end = q; | 
					
						
							|  |  |  |     c->state = HTTPSTATE_SEND_HEADER; | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2008-06-19 07:10:44 +00:00
										 |  |  |  send_status: | 
					
						
							|  |  |  |     compute_status(c); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     c->http_error = 200; /* horrible : we use this value to avoid
 | 
					
						
							|  |  |  |                             going to the send data state */ | 
					
						
							|  |  |  |     c->state = HTTPSTATE_SEND_HEADER; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-20 11:04:12 +01:00
										 |  |  | static void fmt_bytecount(AVIOContext *pb, int64_t count) | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     static const char *suffix = " kMGTP"; | 
					
						
							|  |  |  |     const char *s; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++); | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "%"PRId64"%c", count, *s); | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-19 07:10:44 +00:00
										 |  |  | static void compute_status(HTTPContext *c) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     HTTPContext *c1; | 
					
						
							|  |  |  |     FFStream *stream; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     char *p; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     time_t ti; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     int i, len; | 
					
						
							| 
									
										
										
										
											2011-02-20 11:04:12 +01:00
										 |  |  |     AVIOContext *pb; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-17 08:13:34 +01:00
										 |  |  |     if (avio_open_dyn_buf(&pb) < 0) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         /* XXX: return an error ? */ | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         c->buffer_ptr = c->buffer; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         c->buffer_end = c->buffer; | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "HTTP/1.0 200 OK\r\n"); | 
					
						
							|  |  |  |     avio_printf(pb, "Content-type: %s\r\n", "text/html"); | 
					
						
							|  |  |  |     avio_printf(pb, "Pragma: no-cache\r\n"); | 
					
						
							|  |  |  |     avio_printf(pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name); | 
					
						
							| 
									
										
										
										
											2008-06-22 00:30:48 +00:00
										 |  |  |     if (c->stream->feed_filename[0]) | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |         avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename); | 
					
						
							|  |  |  |     avio_printf(pb, "</head>\n<body>"); | 
					
						
							|  |  |  |     avio_printf(pb, "<h1>%s Status</h1>\n", program_name); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* format status */ | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "<h2>Available Streams</h2>\n"); | 
					
						
							|  |  |  |     avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n"); | 
					
						
							|  |  |  |     avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     stream = first_stream; | 
					
						
							|  |  |  |     while (stream != NULL) { | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         char sfilename[1024]; | 
					
						
							|  |  |  |         char *eosf; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |         if (stream->feed != stream) { | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |             av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |             eosf = sfilename + strlen(sfilename); | 
					
						
							|  |  |  |             if (eosf - sfilename >= 4) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 if (strcmp(eosf - 4, ".asf") == 0) | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                     strcpy(eosf - 4, ".asx"); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 else if (strcmp(eosf - 3, ".rm") == 0) | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                     strcpy(eosf - 3, ".ram"); | 
					
						
							| 
									
										
										
										
											2007-09-17 12:47:44 +00:00
										 |  |  |                 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) { | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                     /* generate a sample RTSP director if
 | 
					
						
							|  |  |  |                        unicast. Generate an SDP redirector if | 
					
						
							|  |  |  |                        multicast */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                     eosf = strrchr(sfilename, '.'); | 
					
						
							|  |  |  |                     if (!eosf) | 
					
						
							|  |  |  |                         eosf = sfilename + strlen(sfilename); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                     if (stream->is_multicast) | 
					
						
							|  |  |  |                         strcpy(eosf, ".sdp"); | 
					
						
							|  |  |  |                     else | 
					
						
							|  |  |  |                         strcpy(eosf, ".rtsp"); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |             avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ", | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                          sfilename, stream->filename); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |             avio_printf(pb, "<td align=right> %d <td align=right> ", | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |                         stream->conns_served); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             fmt_bytecount(pb, stream->bytes_served); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |             switch(stream->stream_type) { | 
					
						
							| 
									
										
										
										
											2008-06-23 08:12:15 +00:00
										 |  |  |             case STREAM_TYPE_LIVE: { | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                     int audio_bit_rate = 0; | 
					
						
							|  |  |  |                     int video_bit_rate = 0; | 
					
						
							| 
									
										
										
										
											2002-11-14 19:07:25 +00:00
										 |  |  |                     const char *audio_codec_name = ""; | 
					
						
							|  |  |  |                     const char *video_codec_name = ""; | 
					
						
							|  |  |  |                     const char *audio_codec_name_extra = ""; | 
					
						
							|  |  |  |                     const char *video_codec_name_extra = ""; | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     for(i=0;i<stream->nb_streams;i++) { | 
					
						
							|  |  |  |                         AVStream *st = stream->streams[i]; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                         AVCodec *codec = avcodec_find_encoder(st->codec->codec_id); | 
					
						
							|  |  |  |                         switch(st->codec->codec_type) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                         case AVMEDIA_TYPE_AUDIO: | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                             audio_bit_rate += st->codec->bit_rate; | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                             if (codec) { | 
					
						
							|  |  |  |                                 if (*audio_codec_name) | 
					
						
							|  |  |  |                                     audio_codec_name_extra = "..."; | 
					
						
							|  |  |  |                                 audio_codec_name = codec->name; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                             break; | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                         case AVMEDIA_TYPE_VIDEO: | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                             video_bit_rate += st->codec->bit_rate; | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                             if (codec) { | 
					
						
							|  |  |  |                                 if (*video_codec_name) | 
					
						
							|  |  |  |                                     video_codec_name_extra = "..."; | 
					
						
							|  |  |  |                                 video_codec_name = codec->name; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                             break; | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                         case AVMEDIA_TYPE_DATA: | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                             video_bit_rate += st->codec->bit_rate; | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                             break; | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                         default: | 
					
						
							| 
									
										
										
										
											2007-07-02 07:43:23 +00:00
										 |  |  |                             abort(); | 
					
						
							| 
									
										
										
										
											2002-05-17 01:53:28 +00:00
										 |  |  |                         } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |                     avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s", | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                                  stream->fmt->name, | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                                  stream->bandwidth, | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                                  video_bit_rate / 1000, video_codec_name, video_codec_name_extra, | 
					
						
							|  |  |  |                                  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     if (stream->feed) | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |                         avio_printf(pb, "<td>%s", stream->feed->filename); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     else | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |                         avio_printf(pb, "<td>%s", stream->feed_filename); | 
					
						
							|  |  |  |                     avio_printf(pb, "\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |                 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n"); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         stream = stream->next; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "</table>\n"); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     stream = first_stream; | 
					
						
							|  |  |  |     while (stream != NULL) { | 
					
						
							|  |  |  |         if (stream->feed == stream) { | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |             avio_printf(pb, "<h2>Feed %s</h2>", stream->filename); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             if (stream->pid) { | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |                 avio_printf(pb, "Running as pid %d.\n", stream->pid); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | #if defined(linux) && !defined(CONFIG_NOCUTILS)
 | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     FILE *pid_stat; | 
					
						
							|  |  |  |                     char ps_cmd[64]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     /* This is somewhat linux specific I guess */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                     snprintf(ps_cmd, sizeof(ps_cmd), | 
					
						
							|  |  |  |                              "ps -o \"%%cpu,cputime\" --no-headers %d", | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                              stream->pid); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                     pid_stat = popen(ps_cmd, "r"); | 
					
						
							|  |  |  |                     if (pid_stat) { | 
					
						
							|  |  |  |                         char cpuperc[10]; | 
					
						
							|  |  |  |                         char cpuused[64]; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         if (fscanf(pid_stat, "%10s %64s", cpuperc, | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                                    cpuused) == 2) { | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |                             avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n", | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                                          cpuperc, cpuused); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         fclose(pid_stat); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |                 avio_printf(pb, "<p>"); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |             avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n"); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             for (i = 0; i < stream->nb_streams; i++) { | 
					
						
							|  |  |  |                 AVStream *st = stream->streams[i]; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id); | 
					
						
							| 
									
										
										
										
											2003-02-10 09:44:47 +00:00
										 |  |  |                 const char *type = "unknown"; | 
					
						
							| 
									
										
										
										
											2002-05-24 02:06:15 +00:00
										 |  |  |                 char parameters[64]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 parameters[0] = 0; | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                 switch(st->codec->codec_type) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                 case AVMEDIA_TYPE_AUDIO: | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                     type = "audio"; | 
					
						
							| 
									
										
										
										
											2007-03-09 11:20:57 +00:00
										 |  |  |                     snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                 case AVMEDIA_TYPE_VIDEO: | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                     type = "video"; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                     snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height, | 
					
						
							|  |  |  |                                 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 default: | 
					
						
							| 
									
										
										
										
											2007-07-02 07:43:23 +00:00
										 |  |  |                     abort(); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |                 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n", | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                         i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |             avio_printf(pb, "</table>\n"); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |         stream = stream->next; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* connection status */ | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "<h2>Connection Status</h2>\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "Number of connections: %d / %d<br>\n", | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                  nb_connections, nb_max_connections); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n", | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                  current_bandwidth, max_bandwidth); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "<table>\n"); | 
					
						
							|  |  |  |     avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     c1 = first_http_ctx; | 
					
						
							|  |  |  |     i = 0; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     while (c1 != NULL) { | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         int bitrate; | 
					
						
							|  |  |  |         int j; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bitrate = 0; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         if (c1->stream) { | 
					
						
							|  |  |  |             for (j = 0; j < c1->stream->nb_streams; j++) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:23:40 +00:00
										 |  |  |                 if (!c1->stream->feed) | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                     bitrate += c1->stream->streams[j]->codec->bit_rate; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:23:40 +00:00
										 |  |  |                 else if (c1->feed_streams[j] >= 0) | 
					
						
							|  |  |  |                     bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         i++; | 
					
						
							|  |  |  |         p = inet_ntoa(c1->from_addr.sin_addr); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |         avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>", | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                     i, | 
					
						
							|  |  |  |                     c1->stream ? c1->stream->filename : "", | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                     c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                     p, | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                     c1->protocol, | 
					
						
							|  |  |  |                     http_state[c1->state]); | 
					
						
							|  |  |  |         fmt_bytecount(pb, bitrate); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |         avio_printf(pb, "<td align=right>"); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |         avio_printf(pb, "<td align=right>"); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         fmt_bytecount(pb, c1->data_count); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |         avio_printf(pb, "\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         c1 = c1->next; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "</table>\n"); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* date */ | 
					
						
							|  |  |  |     ti = time(NULL); | 
					
						
							|  |  |  |     p = ctime(&ti); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(pb, "<hr size=1 noshade>Generated at %s", p); | 
					
						
							|  |  |  |     avio_printf(pb, "</body>\n</html>\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-17 08:16:07 +01:00
										 |  |  |     len = avio_close_dyn_buf(pb, &c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->buffer_ptr = c->pb_buffer; | 
					
						
							|  |  |  |     c->buffer_end = c->pb_buffer + len; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | /* check if the parser needs to be opened for stream i */ | 
					
						
							|  |  |  | static void open_parser(AVFormatContext *s, int i) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     AVStream *st = s->streams[i]; | 
					
						
							|  |  |  |     AVCodec *codec; | 
					
						
							| 
									
										
										
										
											2002-05-30 20:37:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |     if (!st->codec->codec) { | 
					
						
							|  |  |  |         codec = avcodec_find_decoder(st->codec->codec_id); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) { | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |             st->codec->parse_only = 1; | 
					
						
							| 
									
										
										
										
											2011-05-22 14:10:49 +02:00
										 |  |  |             if (avcodec_open2(st->codec, codec, NULL) < 0) | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                 st->codec->parse_only = 0; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int open_input_stream(HTTPContext *c, const char *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char buf[128]; | 
					
						
							|  |  |  |     char input_filename[1024]; | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |     AVFormatContext *s = NULL; | 
					
						
							| 
									
										
										
										
											2011-07-06 22:13:10 +02:00
										 |  |  |     int i, ret; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     int64_t stream_pos; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* find file name */ | 
					
						
							|  |  |  |     if (c->stream->feed) { | 
					
						
							|  |  |  |         strcpy(input_filename, c->stream->feed->feed_filename); | 
					
						
							|  |  |  |         /* compute position (absolute time) */ | 
					
						
							| 
									
										
										
										
											2011-02-16 09:52:38 +01:00
										 |  |  |         if (av_find_info_tag(buf, sizeof(buf), "date", info)) { | 
					
						
							| 
									
										
										
										
											2011-02-16 08:52:37 +00:00
										 |  |  |             if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) | 
					
						
							|  |  |  |                 return ret; | 
					
						
							| 
									
										
										
										
											2011-02-16 09:52:38 +01:00
										 |  |  |         } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) { | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |             int prebuffer = strtol(buf, 0, 10); | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |             stream_pos = av_gettime() - prebuffer * (int64_t)1000000; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         } else | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |             stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         strcpy(input_filename, c->stream->feed_filename); | 
					
						
							|  |  |  |         /* compute position (relative time) */ | 
					
						
							| 
									
										
										
										
											2011-02-16 09:52:38 +01:00
										 |  |  |         if (av_find_info_tag(buf, sizeof(buf), "date", info)) { | 
					
						
							| 
									
										
										
										
											2011-02-16 08:52:37 +00:00
										 |  |  |             if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) | 
					
						
							|  |  |  |                 return ret; | 
					
						
							| 
									
										
										
										
											2008-06-23 08:12:15 +00:00
										 |  |  |         } else | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             stream_pos = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (input_filename[0] == '\0') | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* open stream */ | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |     if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) { | 
					
						
							| 
									
										
										
										
											2008-05-25 00:12:53 +00:00
										 |  |  |         http_log("could not open %s: %d\n", input_filename, ret); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-09-17 07:50:04 +00:00
										 |  |  |     s->flags |= AVFMT_FLAG_GENPTS; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     c->fmt_in = s; | 
					
						
							| 
									
										
										
										
											2009-03-21 09:58:07 +00:00
										 |  |  |     if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) { | 
					
						
							| 
									
										
										
										
											2009-03-20 01:07:22 +00:00
										 |  |  |         http_log("Could not find stream info '%s'\n", input_filename); | 
					
						
							|  |  |  |         av_close_input_file(s); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* open each parser */ | 
					
						
							|  |  |  |     for(i=0;i<s->nb_streams;i++) | 
					
						
							|  |  |  |         open_parser(s, i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* choose stream as clock source (we favorize video stream if
 | 
					
						
							|  |  |  |        present) for packet sending */ | 
					
						
							|  |  |  |     c->pts_stream_index = 0; | 
					
						
							|  |  |  |     for(i=0;i<c->stream->nb_streams;i++) { | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         if (c->pts_stream_index == 0 && | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |             c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             c->pts_stream_index = i; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     if (c->fmt_in->iformat->read_seek) | 
					
						
							| 
									
										
										
										
											2008-06-22 00:22:21 +00:00
										 |  |  |         av_seek_frame(c->fmt_in, -1, stream_pos, 0); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* set the start time (needed for maxtime and RTP packet timing) */ | 
					
						
							|  |  |  |     c->start_time = cur_time; | 
					
						
							|  |  |  |     c->first_pts = AV_NOPTS_VALUE; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  | /* return the server clock (in us) */ | 
					
						
							|  |  |  | static int64_t get_server_clock(HTTPContext *c) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |     /* compute current pts value from system time */ | 
					
						
							| 
									
										
										
										
											2007-02-24 02:39:57 +00:00
										 |  |  |     return (cur_time - c->start_time) * 1000; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  | /* return the estimated time at which the current packet must be sent
 | 
					
						
							|  |  |  |    (in us) */ | 
					
						
							|  |  |  | static int64_t get_packet_send_clock(HTTPContext *c) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |     int bytes_left, bytes_sent, frame_bytes; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |     frame_bytes = c->cur_frame_bytes; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     if (frame_bytes <= 0) | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |         return c->cur_pts; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     else { | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |         bytes_left = c->buffer_end - c->buffer_ptr; | 
					
						
							|  |  |  |         bytes_sent = frame_bytes - bytes_left; | 
					
						
							|  |  |  |         return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int http_prepare_data(HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i, len, ret; | 
					
						
							|  |  |  |     AVFormatContext *ctx; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     av_freep(&c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     switch(c->state) { | 
					
						
							|  |  |  |     case HTTPSTATE_SEND_DATA_HEADER: | 
					
						
							|  |  |  |         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx)); | 
					
						
							| 
									
										
										
										
											2011-05-22 12:46:29 +02:00
										 |  |  |         av_dict_set(&c->fmt_ctx.metadata, "author"   , c->stream->author   , 0); | 
					
						
							|  |  |  |         av_dict_set(&c->fmt_ctx.metadata, "comment"  , c->stream->comment  , 0); | 
					
						
							|  |  |  |         av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0); | 
					
						
							|  |  |  |         av_dict_set(&c->fmt_ctx.metadata, "title"    , c->stream->title    , 0); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-18 11:03:10 -04:00
										 |  |  |         c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-22 03:42:23 +00:00
										 |  |  |         for(i=0;i<c->stream->nb_streams;i++) { | 
					
						
							| 
									
										
										
										
											2005-12-22 01:10:11 +00:00
										 |  |  |             AVStream *src; | 
					
						
							| 
									
										
										
										
											2011-05-18 11:03:10 -04:00
										 |  |  |             c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream)); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             /* if file or feed, then just take streams from FFStream struct */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |             if (!c->stream->feed || | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 c->stream->feed == c->stream) | 
					
						
							| 
									
										
										
										
											2005-01-03 02:42:02 +00:00
										 |  |  |                 src = c->stream->streams[i]; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             else | 
					
						
							| 
									
										
										
										
											2005-01-03 02:42:02 +00:00
										 |  |  |                 src = c->stream->feed->streams[c->stream->feed_streams[i]]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-18 11:03:10 -04:00
										 |  |  |             *(c->fmt_ctx.streams[i]) = *src; | 
					
						
							|  |  |  |             c->fmt_ctx.streams[i]->priv_data = 0; | 
					
						
							|  |  |  |             c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                                            AVStream, not in codec */ | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-06-22 03:42:23 +00:00
										 |  |  |         /* set output format parameters */ | 
					
						
							|  |  |  |         c->fmt_ctx.oformat = c->stream->fmt; | 
					
						
							|  |  |  |         c->fmt_ctx.nb_streams = c->stream->nb_streams; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         c->got_key_frame = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* prepare header and save header data in a stream */ | 
					
						
							| 
									
										
										
										
											2011-03-17 08:13:34 +01:00
										 |  |  |         if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             /* XXX: potential leak */ | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-03-05 21:06:46 +01:00
										 |  |  |         c->fmt_ctx.pb->seekable = 0; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-21 03:43:16 +00:00
										 |  |  |         /*
 | 
					
						
							|  |  |  |          * HACK to avoid mpeg ps muxer to spit many underflow errors | 
					
						
							| 
									
										
										
										
											2011-04-23 16:39:03 +02:00
										 |  |  |          * Default value from Libav | 
					
						
							| 
									
										
										
										
											2008-06-21 03:43:16 +00:00
										 |  |  |          * Try to set it use configuration option | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE); | 
					
						
							|  |  |  |         c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |         if (avformat_write_header(&c->fmt_ctx, NULL) < 0) { | 
					
						
							| 
									
										
										
										
											2008-05-30 00:50:39 +00:00
										 |  |  |             http_log("Error writing output header\n"); | 
					
						
							| 
									
										
										
										
											2007-02-24 02:24:42 +00:00
										 |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2008-05-30 00:50:39 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-05-22 12:46:29 +02:00
										 |  |  |         av_dict_free(&c->fmt_ctx.metadata); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-17 08:16:07 +01:00
										 |  |  |         len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         c->buffer_ptr = c->pb_buffer; | 
					
						
							|  |  |  |         c->buffer_end = c->pb_buffer + len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         c->state = HTTPSTATE_SEND_DATA; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         c->last_packet_sent = 0; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case HTTPSTATE_SEND_DATA: | 
					
						
							|  |  |  |         /* find a new packet */ | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |         /* read a packet from the input stream */ | 
					
						
							|  |  |  |         if (c->stream->feed) | 
					
						
							|  |  |  |             ffm_set_write_index(c->fmt_in, | 
					
						
							|  |  |  |                                 c->stream->feed->feed_write_index, | 
					
						
							|  |  |  |                                 c->stream->feed->feed_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (c->stream->max_time && | 
					
						
							|  |  |  |             c->stream->max_time + c->start_time - cur_time < 0) | 
					
						
							|  |  |  |             /* We have timed out */ | 
					
						
							|  |  |  |             c->state = HTTPSTATE_SEND_DATA_TRAILER; | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             AVPacket pkt; | 
					
						
							|  |  |  |         redo: | 
					
						
							| 
									
										
										
										
											2010-06-16 01:12:26 +00:00
										 |  |  |             ret = av_read_frame(c->fmt_in, &pkt); | 
					
						
							|  |  |  |             if (ret < 0) { | 
					
						
							|  |  |  |                 if (c->stream->feed) { | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     /* if coming from feed, it means we reached the end of the
 | 
					
						
							|  |  |  |                        ffm file, so must wait for more data */ | 
					
						
							|  |  |  |                     c->state = HTTPSTATE_WAIT_FEED; | 
					
						
							|  |  |  |                     return 1; /* state changed */ | 
					
						
							| 
									
										
										
										
											2010-06-16 01:12:26 +00:00
										 |  |  |                 } else if (ret == AVERROR(EAGAIN)) { | 
					
						
							|  |  |  |                     /* input not ready, come back later */ | 
					
						
							|  |  |  |                     return 0; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     if (c->stream->loop) { | 
					
						
							|  |  |  |                         av_close_input_file(c->fmt_in); | 
					
						
							|  |  |  |                         c->fmt_in = NULL; | 
					
						
							|  |  |  |                         if (open_input_stream(c, "") < 0) | 
					
						
							|  |  |  |                             goto no_loop; | 
					
						
							|  |  |  |                         goto redo; | 
					
						
							|  |  |  |                     } else { | 
					
						
							|  |  |  |                     no_loop: | 
					
						
							|  |  |  |                         /* must send trailer now because eof or error */ | 
					
						
							|  |  |  |                         c->state = HTTPSTATE_SEND_DATA_TRAILER; | 
					
						
							| 
									
										
										
										
											2003-07-11 22:30:12 +00:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2008-05-30 01:44:35 +00:00
										 |  |  |                 int source_index = pkt.stream_index; | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                 /* update first pts if needed */ | 
					
						
							|  |  |  |                 if (c->first_pts == AV_NOPTS_VALUE) { | 
					
						
							|  |  |  |                     c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q); | 
					
						
							|  |  |  |                     c->start_time = cur_time; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 /* send it to the appropriate stream */ | 
					
						
							|  |  |  |                 if (c->stream->feed) { | 
					
						
							|  |  |  |                     /* if coming from a feed, select the right stream */ | 
					
						
							|  |  |  |                     if (c->switch_pending) { | 
					
						
							|  |  |  |                         c->switch_pending = 0; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                         for(i=0;i<c->stream->nb_streams;i++) { | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                             if (c->switch_feed_streams[i] == pkt.stream_index) | 
					
						
							| 
									
										
										
										
											2010-03-31 12:29:58 +00:00
										 |  |  |                                 if (pkt.flags & AV_PKT_FLAG_KEY) | 
					
						
							| 
									
										
										
										
											2011-01-23 08:53:40 +01:00
										 |  |  |                                     c->switch_feed_streams[i] = -1; | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                             if (c->switch_feed_streams[i] >= 0) | 
					
						
							|  |  |  |                                 c->switch_pending = 1; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                         } | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     } | 
					
						
							|  |  |  |                     for(i=0;i<c->stream->nb_streams;i++) { | 
					
						
							| 
									
										
										
										
											2010-05-24 20:08:02 +00:00
										 |  |  |                         if (c->stream->feed_streams[i] == pkt.stream_index) { | 
					
						
							| 
									
										
										
										
											2008-05-30 02:32:58 +00:00
										 |  |  |                             AVStream *st = c->fmt_in->streams[source_index]; | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                             pkt.stream_index = i; | 
					
						
							| 
									
										
										
										
											2010-03-31 12:29:58 +00:00
										 |  |  |                             if (pkt.flags & AV_PKT_FLAG_KEY && | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                                 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || | 
					
						
							| 
									
										
										
										
											2008-05-30 17:53:50 +00:00
										 |  |  |                                  c->stream->nb_streams == 1)) | 
					
						
							| 
									
										
										
										
											2008-05-30 02:26:07 +00:00
										 |  |  |                                 c->got_key_frame = 1; | 
					
						
							|  |  |  |                             if (!c->stream->send_on_key || c->got_key_frame) | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                                 goto send_it; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     AVCodecContext *codec; | 
					
						
							| 
									
										
										
										
											2008-06-23 03:21:40 +00:00
										 |  |  |                     AVStream *ist, *ost; | 
					
						
							|  |  |  |                 send_it: | 
					
						
							|  |  |  |                     ist = c->fmt_in->streams[source_index]; | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     /* specific handling for RTP: we use several
 | 
					
						
							|  |  |  |                        output stream (one for each RTP | 
					
						
							|  |  |  |                        connection). XXX: need more abstract handling */ | 
					
						
							|  |  |  |                     if (c->is_packetized) { | 
					
						
							|  |  |  |                         /* compute send time and duration */ | 
					
						
							| 
									
										
										
										
											2008-06-23 03:18:24 +00:00
										 |  |  |                         c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q); | 
					
						
							| 
									
										
										
										
											2010-06-03 20:58:22 +00:00
										 |  |  |                         c->cur_pts -= c->first_pts; | 
					
						
							| 
									
										
										
										
											2008-06-23 03:18:24 +00:00
										 |  |  |                         c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q); | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                         /* find RTP context */ | 
					
						
							|  |  |  |                         c->packet_stream_index = pkt.stream_index; | 
					
						
							|  |  |  |                         ctx = c->rtp_ctx[c->packet_stream_index]; | 
					
						
							|  |  |  |                         if(!ctx) { | 
					
						
							| 
									
										
										
										
											2008-05-21 20:50:41 +00:00
										 |  |  |                             av_free_packet(&pkt); | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                             break; | 
					
						
							| 
									
										
										
										
											2008-05-21 20:50:41 +00:00
										 |  |  |                         } | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                         codec = ctx->streams[0]->codec; | 
					
						
							|  |  |  |                         /* only one stream per RTP connection */ | 
					
						
							|  |  |  |                         pkt.stream_index = 0; | 
					
						
							|  |  |  |                     } else { | 
					
						
							|  |  |  |                         ctx = &c->fmt_ctx; | 
					
						
							|  |  |  |                         /* Fudge here */ | 
					
						
							| 
									
										
										
										
											2008-06-23 07:28:49 +00:00
										 |  |  |                         codec = ctx->streams[pkt.stream_index]->codec; | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (c->is_packetized) { | 
					
						
							|  |  |  |                         int max_packet_size; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |                         if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                             max_packet_size = RTSP_TCP_MAX_PACKET_SIZE; | 
					
						
							|  |  |  |                         else | 
					
						
							|  |  |  |                             max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]); | 
					
						
							| 
									
										
										
										
											2011-03-17 08:19:54 +01:00
										 |  |  |                         ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size); | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     } else { | 
					
						
							| 
									
										
										
										
											2011-03-17 08:13:34 +01:00
										 |  |  |                         ret = avio_open_dyn_buf(&ctx->pb); | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     } | 
					
						
							|  |  |  |                     if (ret < 0) { | 
					
						
							|  |  |  |                         /* XXX: potential leak */ | 
					
						
							|  |  |  |                         return -1; | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2008-06-23 07:28:49 +00:00
										 |  |  |                     ost = ctx->streams[pkt.stream_index]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-05 21:06:46 +01:00
										 |  |  |                     ctx->pb->seekable = 0; | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     if (pkt.dts != AV_NOPTS_VALUE) | 
					
						
							| 
									
										
										
										
											2008-06-23 02:41:06 +00:00
										 |  |  |                         pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base); | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     if (pkt.pts != AV_NOPTS_VALUE) | 
					
						
							| 
									
										
										
										
											2008-06-23 02:41:06 +00:00
										 |  |  |                         pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base); | 
					
						
							|  |  |  |                     pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base); | 
					
						
							| 
									
										
										
										
											2008-05-30 01:46:57 +00:00
										 |  |  |                     if (av_write_frame(ctx, &pkt) < 0) { | 
					
						
							|  |  |  |                         http_log("Error writing frame to output\n"); | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                         c->state = HTTPSTATE_SEND_DATA_TRAILER; | 
					
						
							| 
									
										
										
										
											2008-05-30 01:46:57 +00:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-17 08:16:07 +01:00
										 |  |  |                     len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                     c->cur_frame_bytes = len; | 
					
						
							|  |  |  |                     c->buffer_ptr = c->pb_buffer; | 
					
						
							|  |  |  |                     c->buffer_end = c->pb_buffer + len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     codec->frame_number++; | 
					
						
							|  |  |  |                     if (len == 0) { | 
					
						
							|  |  |  |                         av_free_packet(&pkt); | 
					
						
							|  |  |  |                         goto redo; | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |                 av_free_packet(&pkt); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-05-29 23:11:25 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |     case HTTPSTATE_SEND_DATA_TRAILER: | 
					
						
							|  |  |  |         /* last packet test ? */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         if (c->last_packet_sent || c->is_packetized) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         ctx = &c->fmt_ctx; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         /* prepare header */ | 
					
						
							| 
									
										
										
										
											2011-03-17 08:13:34 +01:00
										 |  |  |         if (avio_open_dyn_buf(&ctx->pb) < 0) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             /* XXX: potential leak */ | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-03-05 21:06:46 +01:00
										 |  |  |         c->fmt_ctx.pb->seekable = 0; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         av_write_trailer(ctx); | 
					
						
							| 
									
										
										
										
											2011-03-17 08:16:07 +01:00
										 |  |  |         len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         c->buffer_ptr = c->pb_buffer; | 
					
						
							|  |  |  |         c->buffer_end = c->pb_buffer + len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         c->last_packet_sent = 1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* should convert the format at the same time */ | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  | /* send data starting at c->buffer_ptr to the output connection
 | 
					
						
							|  |  |  |    (either UDP or TCP connection) */ | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | static int http_send_data(HTTPContext *c) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |     int len, ret; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     for(;;) { | 
					
						
							|  |  |  |         if (c->buffer_ptr >= c->buffer_end) { | 
					
						
							|  |  |  |             ret = http_prepare_data(c); | 
					
						
							|  |  |  |             if (ret < 0) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             else if (ret != 0) | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                 /* state change requested */ | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |             if (c->is_packetized) { | 
					
						
							|  |  |  |                 /* RTP data output */ | 
					
						
							|  |  |  |                 len = c->buffer_end - c->buffer_ptr; | 
					
						
							|  |  |  |                 if (len < 4) { | 
					
						
							|  |  |  |                     /* fail safe - should never happen */ | 
					
						
							|  |  |  |                 fail1: | 
					
						
							|  |  |  |                     c->buffer_ptr = c->buffer_end; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                     return 0; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                 len = (c->buffer_ptr[0] << 24) | | 
					
						
							|  |  |  |                     (c->buffer_ptr[1] << 16) | | 
					
						
							|  |  |  |                     (c->buffer_ptr[2] << 8) | | 
					
						
							|  |  |  |                     (c->buffer_ptr[3]); | 
					
						
							|  |  |  |                 if (len > (c->buffer_end - c->buffer_ptr)) | 
					
						
							|  |  |  |                     goto fail1; | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) { | 
					
						
							|  |  |  |                     /* nothing to send yet: we can wait */ | 
					
						
							|  |  |  |                     return 0; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 c->data_count += len; | 
					
						
							|  |  |  |                 update_datarate(&c->datarate, c->data_count); | 
					
						
							|  |  |  |                 if (c->stream) | 
					
						
							|  |  |  |                     c->stream->bytes_served += len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |                 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) { | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                     /* RTP packets are sent inside the RTSP TCP connection */ | 
					
						
							| 
									
										
										
										
											2011-02-20 11:04:12 +01:00
										 |  |  |                     AVIOContext *pb; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                     int interleaved_index, size; | 
					
						
							|  |  |  |                     uint8_t header[4]; | 
					
						
							|  |  |  |                     HTTPContext *rtsp_c; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                     rtsp_c = c->rtsp_c; | 
					
						
							|  |  |  |                     /* if no RTSP connection left, error */ | 
					
						
							|  |  |  |                     if (!rtsp_c) | 
					
						
							|  |  |  |                         return -1; | 
					
						
							|  |  |  |                     /* if already sending something, then wait. */ | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                         break; | 
					
						
							| 
									
										
										
										
											2011-03-17 08:13:34 +01:00
										 |  |  |                     if (avio_open_dyn_buf(&pb) < 0) | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                         goto fail1; | 
					
						
							|  |  |  |                     interleaved_index = c->packet_stream_index * 2; | 
					
						
							|  |  |  |                     /* RTCP packets are sent at odd indexes */ | 
					
						
							|  |  |  |                     if (c->buffer_ptr[1] == 200) | 
					
						
							|  |  |  |                         interleaved_index++; | 
					
						
							|  |  |  |                     /* write RTSP TCP header */ | 
					
						
							|  |  |  |                     header[0] = '$'; | 
					
						
							|  |  |  |                     header[1] = interleaved_index; | 
					
						
							|  |  |  |                     header[2] = len >> 8; | 
					
						
							|  |  |  |                     header[3] = len; | 
					
						
							| 
									
										
										
										
											2011-02-21 19:28:17 +01:00
										 |  |  |                     avio_write(pb, header, 4); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                     /* write RTP packet data */ | 
					
						
							|  |  |  |                     c->buffer_ptr += 4; | 
					
						
							| 
									
										
										
										
											2011-02-21 19:28:17 +01:00
										 |  |  |                     avio_write(pb, c->buffer_ptr, len); | 
					
						
							| 
									
										
										
										
											2011-03-17 08:16:07 +01:00
										 |  |  |                     size = avio_close_dyn_buf(pb, &c->packet_buffer); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                     /* prepare asynchronous TCP sending */ | 
					
						
							|  |  |  |                     rtsp_c->packet_buffer_ptr = c->packet_buffer; | 
					
						
							|  |  |  |                     rtsp_c->packet_buffer_end = c->packet_buffer + size; | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                     c->buffer_ptr += len; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                     /* send everything we can NOW */ | 
					
						
							| 
									
										
										
										
											2007-02-22 12:38:37 +00:00
										 |  |  |                     len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr, | 
					
						
							|  |  |  |                                 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     if (len > 0) | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                         rtsp_c->packet_buffer_ptr += len; | 
					
						
							|  |  |  |                     if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) { | 
					
						
							|  |  |  |                         /* if we could not send all the data, we will
 | 
					
						
							|  |  |  |                            send it later, so a new state is needed to | 
					
						
							|  |  |  |                            "lock" the RTSP TCP connection */ | 
					
						
							|  |  |  |                         rtsp_c->state = RTSPSTATE_SEND_PACKET; | 
					
						
							|  |  |  |                         break; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     } else | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                         /* all data has been sent */ | 
					
						
							|  |  |  |                         av_freep(&c->packet_buffer); | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     /* send RTP packet directly in UDP */ | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                     c->buffer_ptr += 4; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                     url_write(c->rtp_handles[c->packet_stream_index], | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                               c->buffer_ptr, len); | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                     c->buffer_ptr += len; | 
					
						
							|  |  |  |                     /* here we continue as we can send several packets per 10 ms slot */ | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 /* TCP data output */ | 
					
						
							| 
									
										
										
										
											2007-02-22 12:38:37 +00:00
										 |  |  |                 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                 if (len < 0) { | 
					
						
							| 
									
										
										
										
											2011-02-19 19:14:11 +01:00
										 |  |  |                     if (ff_neterrno() != AVERROR(EAGAIN) && | 
					
						
							|  |  |  |                         ff_neterrno() != AVERROR(EINTR)) | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                         /* error : close connection */ | 
					
						
							|  |  |  |                         return -1; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     else | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                         return 0; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 } else | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                     c->buffer_ptr += len; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                 c->data_count += len; | 
					
						
							|  |  |  |                 update_datarate(&c->datarate, c->data_count); | 
					
						
							|  |  |  |                 if (c->stream) | 
					
						
							|  |  |  |                     c->stream->bytes_served += len; | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     } /* for(;;) */ | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int http_start_receive_data(HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (c->stream->feed_opened) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |     /* Don't permit writing to this one */ | 
					
						
							|  |  |  |     if (c->stream->readonly) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* open feed */ | 
					
						
							|  |  |  |     fd = open(c->stream->feed_filename, O_RDWR); | 
					
						
							| 
									
										
										
										
											2008-05-30 00:50:39 +00:00
										 |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         http_log("Error opening feeder file: %s\n", strerror(errno)); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2008-05-30 00:50:39 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     c->feed_fd = fd; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 10:28:49 +00:00
										 |  |  |     if (c->stream->truncate) { | 
					
						
							|  |  |  |         /* truncate feed file */ | 
					
						
							|  |  |  |         ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE); | 
					
						
							|  |  |  |         ftruncate(c->feed_fd, FFM_PACKET_SIZE); | 
					
						
							|  |  |  |         http_log("Truncating feed file '%s'\n", c->stream->feed_filename); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2009-03-21 10:29:37 +00:00
										 |  |  |         if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) { | 
					
						
							|  |  |  |             http_log("Error reading write index from feed file: %s\n", strerror(errno)); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-03-21 10:28:49 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 06:52:55 +00:00
										 |  |  |     c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     c->stream->feed_size = lseek(fd, 0, SEEK_END); | 
					
						
							|  |  |  |     lseek(fd, 0, SEEK_SET); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* init buffer input */ | 
					
						
							|  |  |  |     c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |     c->buffer_end = c->buffer + FFM_PACKET_SIZE; | 
					
						
							|  |  |  |     c->stream->feed_opened = 1; | 
					
						
							| 
									
										
										
										
											2010-03-06 19:41:24 +00:00
										 |  |  |     c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | static int http_receive_data(HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     HTTPContext *c1; | 
					
						
							| 
									
										
										
										
											2010-03-03 18:41:50 +00:00
										 |  |  |     int len, loop_run = 0; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-03 18:41:50 +00:00
										 |  |  |     while (c->chunked_encoding && !c->chunk_size && | 
					
						
							|  |  |  |            c->buffer_end > c->buffer_ptr) { | 
					
						
							|  |  |  |         /* read chunk header, if present */ | 
					
						
							|  |  |  |         len = recv(c->fd, c->buffer_ptr, 1, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (len < 0) { | 
					
						
							| 
									
										
										
										
											2011-02-19 19:14:11 +01:00
										 |  |  |             if (ff_neterrno() != AVERROR(EAGAIN) && | 
					
						
							|  |  |  |                 ff_neterrno() != AVERROR(EINTR)) | 
					
						
							| 
									
										
										
										
											2010-03-03 18:41:50 +00:00
										 |  |  |                 /* error : close connection */ | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							| 
									
										
										
										
											2010-05-21 07:59:12 +00:00
										 |  |  |             return 0; | 
					
						
							| 
									
										
										
										
											2010-03-03 18:41:50 +00:00
										 |  |  |         } else if (len == 0) { | 
					
						
							|  |  |  |             /* end of connection : close it */ | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } else if (c->buffer_ptr - c->buffer >= 2 && | 
					
						
							|  |  |  |                    !memcmp(c->buffer_ptr - 1, "\r\n", 2)) { | 
					
						
							|  |  |  |             c->chunk_size = strtol(c->buffer, 0, 16); | 
					
						
							|  |  |  |             if (c->chunk_size == 0) // end of stream
 | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							|  |  |  |             c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } else if (++loop_run > 10) { | 
					
						
							|  |  |  |             /* no chunk header, abort */ | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             c->buffer_ptr++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-03 18:41:50 +00:00
										 |  |  |     if (c->buffer_end > c->buffer_ptr) { | 
					
						
							|  |  |  |         len = recv(c->fd, c->buffer_ptr, | 
					
						
							|  |  |  |                    FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |         if (len < 0) { | 
					
						
							| 
									
										
										
										
											2011-02-19 19:14:11 +01:00
										 |  |  |             if (ff_neterrno() != AVERROR(EAGAIN) && | 
					
						
							|  |  |  |                 ff_neterrno() != AVERROR(EINTR)) | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |                 /* error : close connection */ | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         } else if (len == 0) | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |             /* end of connection : close it */ | 
					
						
							|  |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         else { | 
					
						
							| 
									
										
										
										
											2010-03-03 18:41:50 +00:00
										 |  |  |             c->chunk_size -= len; | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |             c->buffer_ptr += len; | 
					
						
							|  |  |  |             c->data_count += len; | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |             update_datarate(&c->datarate, c->data_count); | 
					
						
							| 
									
										
										
										
											2002-05-18 21:33:05 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |     if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) { | 
					
						
							|  |  |  |         if (c->buffer[0] != 'f' || | 
					
						
							|  |  |  |             c->buffer[1] != 'm') { | 
					
						
							|  |  |  |             http_log("Feed stream has become desynchronized -- disconnecting\n"); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     if (c->buffer_ptr >= c->buffer_end) { | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |         FFStream *feed = c->stream; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         /* a packet has been received : write it in the store, except
 | 
					
						
							|  |  |  |            if header */ | 
					
						
							|  |  |  |         if (c->data_count > FFM_PACKET_SIZE) { | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-01 22:39:58 +00:00
										 |  |  |             //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             /* XXX: use llseek or url_seek */ | 
					
						
							|  |  |  |             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET); | 
					
						
							| 
									
										
										
										
											2008-05-30 00:50:39 +00:00
										 |  |  |             if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) { | 
					
						
							|  |  |  |                 http_log("Error writing to feed file: %s\n", strerror(errno)); | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             feed->feed_write_index += FFM_PACKET_SIZE; | 
					
						
							|  |  |  |             /* update file size */ | 
					
						
							|  |  |  |             if (feed->feed_write_index > c->stream->feed_size) | 
					
						
							|  |  |  |                 feed->feed_size = feed->feed_write_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* handle wrap around if max file size reached */ | 
					
						
							| 
									
										
										
										
											2005-11-13 03:26:43 +00:00
										 |  |  |             if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 feed->feed_write_index = FFM_PACKET_SIZE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* write index */ | 
					
						
							| 
									
										
										
										
											2009-02-12 02:23:25 +00:00
										 |  |  |             if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) { | 
					
						
							|  |  |  |                 http_log("Error writing index to feed file: %s\n", strerror(errno)); | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             /* wake up any waiting connections */ | 
					
						
							|  |  |  |             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) { | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                 if (c1->state == HTTPSTATE_WAIT_FEED && | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                     c1->stream->feed == c->stream->feed) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                     c1->state = HTTPSTATE_SEND_DATA; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             /* We have a header in our hands that contains useful data */ | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |             AVFormatContext *s = avformat_alloc_context(); | 
					
						
							| 
									
										
										
										
											2011-02-20 11:04:12 +01:00
										 |  |  |             AVIOContext *pb; | 
					
						
							| 
									
										
										
										
											2002-05-20 16:33:46 +00:00
										 |  |  |             AVInputFormat *fmt_in; | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |             int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |             if (!s) | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-20 16:33:46 +00:00
										 |  |  |             /* use feed output format name to find corresponding input format */ | 
					
						
							|  |  |  |             fmt_in = av_find_input_format(feed->fmt->name); | 
					
						
							|  |  |  |             if (!fmt_in) | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:04 +01:00
										 |  |  |             pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer, | 
					
						
							|  |  |  |                                     0, NULL, NULL, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2011-03-05 21:06:46 +01:00
										 |  |  |             pb->seekable = 0; | 
					
						
							| 
									
										
										
										
											2008-06-22 03:30:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |             s->pb = pb; | 
					
						
							|  |  |  |             if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-22 03:25:20 +00:00
										 |  |  |                 av_free(pb); | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             /* Now we have the actual streams */ | 
					
						
							| 
									
										
										
										
											2008-06-22 02:31:57 +00:00
										 |  |  |             if (s->nb_streams != feed->nb_streams) { | 
					
						
							|  |  |  |                 av_close_input_stream(s); | 
					
						
							| 
									
										
										
										
											2008-06-22 02:34:33 +00:00
										 |  |  |                 av_free(pb); | 
					
						
							| 
									
										
										
										
											2009-03-20 01:05:51 +00:00
										 |  |  |                 http_log("Feed '%s' stream number does not match registered feed\n", | 
					
						
							|  |  |  |                          c->stream->feed_filename); | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |                 goto fail; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-06-22 02:31:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-23 19:57:58 +00:00
										 |  |  |             for (i = 0; i < s->nb_streams; i++) { | 
					
						
							|  |  |  |                 AVStream *fst = feed->streams[i]; | 
					
						
							|  |  |  |                 AVStream *st = s->streams[i]; | 
					
						
							| 
									
										
										
										
											2010-06-22 06:45:05 +00:00
										 |  |  |                 avcodec_copy_context(fst->codec, st->codec); | 
					
						
							| 
									
										
										
										
											2008-06-23 19:57:58 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-06-22 02:31:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             av_close_input_stream(s); | 
					
						
							| 
									
										
										
										
											2008-06-22 02:34:33 +00:00
										 |  |  |             av_free(pb); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         c->buffer_ptr = c->buffer; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |  fail: | 
					
						
							|  |  |  |     c->stream->feed_opened = 0; | 
					
						
							|  |  |  |     close(c->feed_fd); | 
					
						
							| 
									
										
										
										
											2008-05-30 01:46:06 +00:00
										 |  |  |     /* wake up any waiting connections to stop waiting for feed */ | 
					
						
							|  |  |  |     for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) { | 
					
						
							|  |  |  |         if (c1->state == HTTPSTATE_WAIT_FEED && | 
					
						
							|  |  |  |             c1->stream->feed == c->stream->feed) | 
					
						
							|  |  |  |             c1->state = HTTPSTATE_SEND_DATA_TRAILER; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | /********************************************************************/ | 
					
						
							|  |  |  | /* RTSP handling */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *str; | 
					
						
							|  |  |  |     time_t ti; | 
					
						
							| 
									
										
										
										
											2010-05-18 11:16:12 +00:00
										 |  |  |     struct tm *tm; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     char buf2[32]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch(error_number) { | 
					
						
							| 
									
										
										
										
											2007-04-10 14:36:11 +00:00
										 |  |  |     case RTSP_STATUS_OK: | 
					
						
							|  |  |  |         str = "OK"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_METHOD: | 
					
						
							|  |  |  |         str = "Method Not Allowed"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_BANDWIDTH: | 
					
						
							|  |  |  |         str = "Not Enough Bandwidth"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_SESSION: | 
					
						
							|  |  |  |         str = "Session Not Found"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_STATE: | 
					
						
							|  |  |  |         str = "Method Not Valid in This State"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_AGGREGATE: | 
					
						
							|  |  |  |         str = "Aggregate operation not allowed"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_ONLY_AGGREGATE: | 
					
						
							|  |  |  |         str = "Only aggregate operation allowed"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_TRANSPORT: | 
					
						
							|  |  |  |         str = "Unsupported transport"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_INTERNAL: | 
					
						
							|  |  |  |         str = "Internal Server Error"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_SERVICE: | 
					
						
							|  |  |  |         str = "Service Unavailable"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATUS_VERSION: | 
					
						
							|  |  |  |         str = "RTSP Version not supported"; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     default: | 
					
						
							|  |  |  |         str = "Unknown Error"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str); | 
					
						
							|  |  |  |     avio_printf(c->pb, "CSeq: %d\r\n", c->seq); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* output GMT time */ | 
					
						
							|  |  |  |     ti = time(NULL); | 
					
						
							| 
									
										
										
										
											2010-05-18 11:16:12 +00:00
										 |  |  |     tm = gmtime(&ti); | 
					
						
							|  |  |  |     strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "Date: %s GMT\r\n", buf2); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     rtsp_reply_header(c, error_number); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int rtsp_parse_request(HTTPContext *c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *p, *p1, *p2; | 
					
						
							|  |  |  |     char cmd[32]; | 
					
						
							|  |  |  |     char url[1024]; | 
					
						
							|  |  |  |     char protocol[32]; | 
					
						
							|  |  |  |     char line[1024]; | 
					
						
							|  |  |  |     int len; | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  |     RTSPMessageHeader header1, *header = &header1; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->buffer_ptr[0] = '\0'; | 
					
						
							|  |  |  |     p = c->buffer; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     get_word(cmd, sizeof(cmd), &p); | 
					
						
							|  |  |  |     get_word(url, sizeof(url), &p); | 
					
						
							|  |  |  |     get_word(protocol, sizeof(protocol), &p); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     av_strlcpy(c->method, cmd, sizeof(c->method)); | 
					
						
							|  |  |  |     av_strlcpy(c->url, url, sizeof(c->url)); | 
					
						
							|  |  |  |     av_strlcpy(c->protocol, protocol, sizeof(c->protocol)); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-17 08:13:34 +01:00
										 |  |  |     if (avio_open_dyn_buf(&c->pb) < 0) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         /* XXX: cannot do more */ | 
					
						
							|  |  |  |         c->pb = NULL; /* safety */ | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* check version name */ | 
					
						
							|  |  |  |     if (strcmp(protocol, "RTSP/1.0") != 0) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_VERSION); | 
					
						
							|  |  |  |         goto the_end; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* parse each header line */ | 
					
						
							| 
									
										
										
										
											2009-02-21 14:40:19 +00:00
										 |  |  |     memset(header, 0, sizeof(*header)); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* skip to next line */ | 
					
						
							|  |  |  |     while (*p != '\n' && *p != '\0') | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     if (*p == '\n') | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     while (*p != '\0') { | 
					
						
							| 
									
										
										
										
											2010-05-24 19:23:31 +00:00
										 |  |  |         p1 = memchr(p, '\n', (char *)c->buffer_ptr - p); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         if (!p1) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         p2 = p1; | 
					
						
							|  |  |  |         if (p2 > p && p2[-1] == '\r') | 
					
						
							|  |  |  |             p2--; | 
					
						
							|  |  |  |         /* skip empty line */ | 
					
						
							|  |  |  |         if (p2 == p) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         len = p2 - p; | 
					
						
							|  |  |  |         if (len > sizeof(line) - 1) | 
					
						
							|  |  |  |             len = sizeof(line) - 1; | 
					
						
							|  |  |  |         memcpy(line, p, len); | 
					
						
							|  |  |  |         line[len] = '\0'; | 
					
						
							| 
									
										
										
										
											2011-01-02 10:10:12 +00:00
										 |  |  |         ff_rtsp_parse_line(header, line, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         p = p1 + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* handle sequence number */ | 
					
						
							|  |  |  |     c->seq = header->seq; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     if (!strcmp(cmd, "DESCRIBE")) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         rtsp_cmd_describe(c, url); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     else if (!strcmp(cmd, "OPTIONS")) | 
					
						
							| 
									
										
										
										
											2003-04-04 13:29:58 +00:00
										 |  |  |         rtsp_cmd_options(c, url); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     else if (!strcmp(cmd, "SETUP")) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         rtsp_cmd_setup(c, url, header); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     else if (!strcmp(cmd, "PLAY")) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         rtsp_cmd_play(c, url, header); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     else if (!strcmp(cmd, "PAUSE")) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         rtsp_cmd_pause(c, url, header); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     else if (!strcmp(cmd, "TEARDOWN")) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         rtsp_cmd_teardown(c, url, header); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         rtsp_reply_error(c, RTSP_STATUS_METHOD); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |  the_end: | 
					
						
							| 
									
										
										
										
											2011-03-17 08:16:07 +01:00
										 |  |  |     len = avio_close_dyn_buf(c->pb, &c->pb_buffer); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->pb = NULL; /* safety */ | 
					
						
							|  |  |  |     if (len < 0) { | 
					
						
							|  |  |  |         /* XXX: cannot do more */ | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     c->buffer_ptr = c->pb_buffer; | 
					
						
							|  |  |  |     c->buffer_end = c->pb_buffer + len; | 
					
						
							|  |  |  |     c->state = RTSPSTATE_SEND_REPLY; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer, | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                                    struct in_addr my_ip) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |     AVFormatContext *avc; | 
					
						
							| 
									
										
										
										
											2010-10-15 19:09:05 +00:00
										 |  |  |     AVStream *avs = NULL; | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-08 08:27:26 +00:00
										 |  |  |     avc =  avformat_alloc_context(); | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |     if (avc == NULL) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-05-22 12:46:29 +02:00
										 |  |  |     av_dict_set(&avc->metadata, "title", | 
					
						
							|  |  |  |                stream->title[0] ? stream->title : "No Title", 0); | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |     avc->nb_streams = stream->nb_streams; | 
					
						
							|  |  |  |     if (stream->is_multicast) { | 
					
						
							|  |  |  |         snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d", | 
					
						
							|  |  |  |                  inet_ntoa(stream->multicast_ip), | 
					
						
							|  |  |  |                  stream->multicast_port, stream->multicast_ttl); | 
					
						
							| 
									
										
										
										
											2010-05-17 17:34:13 +00:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         snprintf(avc->filename, 1024, "rtp://0.0.0.0"); | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-15 19:09:05 +00:00
										 |  |  |     if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) || | 
					
						
							|  |  |  |         !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams)))) | 
					
						
							|  |  |  |         goto sdp_done; | 
					
						
							|  |  |  |     if (avc->nb_streams >= INT_MAX/sizeof(*avs) || | 
					
						
							|  |  |  |         !(avs = av_malloc(avc->nb_streams * sizeof(*avs)))) | 
					
						
							|  |  |  |         goto sdp_done; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     for(i = 0; i < stream->nb_streams; i++) { | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |         avc->streams[i] = &avs[i]; | 
					
						
							|  |  |  |         avc->streams[i]->codec = stream->streams[i]->codec; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |     *pbuffer = av_mallocz(2048); | 
					
						
							| 
									
										
										
										
											2011-04-08 11:36:12 +02:00
										 |  |  |     av_sdp_create(&avc, 1, *pbuffer, 2048); | 
					
						
							| 
									
										
										
										
											2010-10-15 19:09:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |  sdp_done: | 
					
						
							|  |  |  |     av_free(avc->streams); | 
					
						
							| 
									
										
										
										
											2011-05-22 12:46:29 +02:00
										 |  |  |     av_dict_free(&avc->metadata); | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  |     av_free(avc); | 
					
						
							| 
									
										
										
										
											2010-10-15 19:09:05 +00:00
										 |  |  |     av_free(avs); | 
					
						
							| 
									
										
										
										
											2007-08-20 07:07:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return strlen(*pbuffer); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-04 13:29:58 +00:00
										 |  |  | static void rtsp_cmd_options(HTTPContext *c, const char *url) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | //    rtsp_reply_header(c, RTSP_STATUS_OK);
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK"); | 
					
						
							|  |  |  |     avio_printf(c->pb, "CSeq: %d\r\n", c->seq); | 
					
						
							|  |  |  |     avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE"); | 
					
						
							|  |  |  |     avio_printf(c->pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2003-04-04 13:29:58 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | static void rtsp_cmd_describe(HTTPContext *c, const char *url) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FFStream *stream; | 
					
						
							|  |  |  |     char path1[1024]; | 
					
						
							|  |  |  |     const char *path; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     uint8_t *content; | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |     int content_length, len; | 
					
						
							|  |  |  |     struct sockaddr_in my_addr; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* find which url is asked */ | 
					
						
							| 
									
										
										
										
											2010-06-27 14:16:46 +00:00
										 |  |  |     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     path = path1; | 
					
						
							|  |  |  |     if (*path == '/') | 
					
						
							|  |  |  |         path++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for(stream = first_stream; stream != NULL; stream = stream->next) { | 
					
						
							| 
									
										
										
										
											2007-09-17 12:47:44 +00:00
										 |  |  |         if (!stream->is_feed && | 
					
						
							|  |  |  |             stream->fmt && !strcmp(stream->fmt->name, "rtp") && | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             !strcmp(path, stream->filename)) { | 
					
						
							|  |  |  |             goto found; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* no stream found */ | 
					
						
							|  |  |  |     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */ | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  found: | 
					
						
							|  |  |  |     /* prepare the media description in sdp format */ | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* get the host IP */ | 
					
						
							|  |  |  |     len = sizeof(my_addr); | 
					
						
							|  |  |  |     getsockname(c->fd, (struct sockaddr *)&my_addr, &len); | 
					
						
							|  |  |  |     content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     if (content_length < 0) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_INTERNAL); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     rtsp_reply_header(c, RTSP_STATUS_OK); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "Content-Base: %s/\r\n", url); | 
					
						
							|  |  |  |     avio_printf(c->pb, "Content-Type: application/sdp\r\n"); | 
					
						
							|  |  |  |     avio_printf(c->pb, "Content-Length: %d\r\n", content_length); | 
					
						
							|  |  |  |     avio_printf(c->pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2011-02-21 19:28:17 +01:00
										 |  |  |     avio_write(c->pb, content, content_length); | 
					
						
							| 
									
										
										
										
											2010-05-24 19:05:22 +00:00
										 |  |  |     av_free(content); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static HTTPContext *find_rtp_session(const char *session_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     HTTPContext *c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (session_id[0] == '\0') | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for(c = first_http_ctx; c != NULL; c = c->next) { | 
					
						
							|  |  |  |         if (!strcmp(c->session_id, session_id)) | 
					
						
							|  |  |  |             return c; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  | static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPTransportField *th; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for(i=0;i<h->nb_transports;i++) { | 
					
						
							|  |  |  |         th = &h->transports[i]; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         if (th->lower_transport == lower_transport) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             return th; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static void rtsp_cmd_setup(HTTPContext *c, const char *url, | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  |                            RTSPMessageHeader *h) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     FFStream *stream; | 
					
						
							| 
									
										
										
										
											2010-04-19 11:42:02 +00:00
										 |  |  |     int stream_index, rtp_port, rtcp_port; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     char buf[1024]; | 
					
						
							|  |  |  |     char path1[1024]; | 
					
						
							|  |  |  |     const char *path; | 
					
						
							|  |  |  |     HTTPContext *rtp_c; | 
					
						
							|  |  |  |     RTSPTransportField *th; | 
					
						
							|  |  |  |     struct sockaddr_in dest_addr; | 
					
						
							|  |  |  |     RTSPActionServerSetup setup; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* find which url is asked */ | 
					
						
							| 
									
										
										
										
											2010-06-27 14:16:46 +00:00
										 |  |  |     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     path = path1; | 
					
						
							|  |  |  |     if (*path == '/') | 
					
						
							|  |  |  |         path++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* now check each stream */ | 
					
						
							|  |  |  |     for(stream = first_stream; stream != NULL; stream = stream->next) { | 
					
						
							| 
									
										
										
										
											2007-09-17 12:47:44 +00:00
										 |  |  |         if (!stream->is_feed && | 
					
						
							|  |  |  |             stream->fmt && !strcmp(stream->fmt->name, "rtp")) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             /* accept aggregate filenames only if single stream */ | 
					
						
							|  |  |  |             if (!strcmp(path, stream->filename)) { | 
					
						
							|  |  |  |                 if (stream->nb_streams != 1) { | 
					
						
							|  |  |  |                     rtsp_reply_error(c, RTSP_STATUS_AGGREGATE); | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 stream_index = 0; | 
					
						
							|  |  |  |                 goto found; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             for(stream_index = 0; stream_index < stream->nb_streams; | 
					
						
							|  |  |  |                 stream_index++) { | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                 snprintf(buf, sizeof(buf), "%s/streamid=%d", | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                          stream->filename, stream_index); | 
					
						
							|  |  |  |                 if (!strcmp(path, buf)) | 
					
						
							|  |  |  |                     goto found; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* no stream found */ | 
					
						
							|  |  |  |     rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */ | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |  found: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* generate session id if needed */ | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     if (h->session_id[0] == '\0') | 
					
						
							| 
									
										
										
										
											2007-02-21 13:50:32 +00:00
										 |  |  |         snprintf(h->session_id, sizeof(h->session_id), "%08x%08x", | 
					
						
							| 
									
										
										
										
											2009-03-20 01:00:53 +00:00
										 |  |  |                  av_lfg_get(&random_state), av_lfg_get(&random_state)); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* find rtp session, and create it if none found */ | 
					
						
							|  |  |  |     rtp_c = find_rtp_session(h->session_id); | 
					
						
							|  |  |  |     if (!rtp_c) { | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         /* always prefer UDP */ | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         if (!th) { | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |             th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |             if (!th) { | 
					
						
							|  |  |  |                 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id, | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |                                    th->lower_transport); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         if (!rtp_c) { | 
					
						
							|  |  |  |             rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* open input stream */ | 
					
						
							|  |  |  |         if (open_input_stream(rtp_c, "") < 0) { | 
					
						
							|  |  |  |             rtsp_reply_error(c, RTSP_STATUS_INTERNAL); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* test if stream is OK (test needed because several SETUP needs
 | 
					
						
							|  |  |  |        to be done for a given file) */ | 
					
						
							|  |  |  |     if (rtp_c->stream != stream) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_SERVICE); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* test if stream is already set up */ | 
					
						
							|  |  |  |     if (rtp_c->rtp_ctx[stream_index]) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_STATE); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* check transport */ | 
					
						
							|  |  |  |     th = find_transport(h, rtp_c->rtp_protocol); | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP && | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 th->client_port_min <= 0)) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* setup default options */ | 
					
						
							|  |  |  |     setup.transport_option[0] = '\0'; | 
					
						
							|  |  |  |     dest_addr = rtp_c->from_addr; | 
					
						
							|  |  |  |     dest_addr.sin_port = htons(th->client_port_min); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* setup stream */ | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* now everything is OK, so we can send the connection parameters */ | 
					
						
							|  |  |  |     rtsp_reply_header(c, RTSP_STATUS_OK); | 
					
						
							|  |  |  |     /* session ID */ | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch(rtp_c->rtp_protocol) { | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     case RTSP_LOWER_TRANSPORT_UDP: | 
					
						
							| 
									
										
										
										
											2010-04-19 11:42:02 +00:00
										 |  |  |         rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]); | 
					
						
							|  |  |  |         rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |         avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;" | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                     "client_port=%d-%d;server_port=%d-%d", | 
					
						
							| 
									
										
										
										
											2010-04-19 11:42:02 +00:00
										 |  |  |                     th->client_port_min, th->client_port_max, | 
					
						
							|  |  |  |                     rtp_port, rtcp_port); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     case RTSP_LOWER_TRANSPORT_TCP: | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |         avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d", | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                     stream_index * 2, stream_index * 2 + 1); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     if (setup.transport_option[0] != '\0') | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |         avio_printf(c->pb, ";%s", setup.transport_option); | 
					
						
							|  |  |  |     avio_printf(c->pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* find an rtp connection by using the session ID. Check consistency
 | 
					
						
							|  |  |  |    with filename */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static HTTPContext *find_rtp_session_with_url(const char *url, | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                                               const char *session_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     HTTPContext *rtp_c; | 
					
						
							|  |  |  |     char path1[1024]; | 
					
						
							|  |  |  |     const char *path; | 
					
						
							| 
									
										
										
										
											2003-06-29 01:25:41 +00:00
										 |  |  |     char buf[1024]; | 
					
						
							| 
									
										
										
										
											2011-02-16 16:37:40 +02:00
										 |  |  |     int s, len; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     rtp_c = find_rtp_session(session_id); | 
					
						
							|  |  |  |     if (!rtp_c) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* find which url is asked */ | 
					
						
							| 
									
										
										
										
											2010-06-27 14:16:46 +00:00
										 |  |  |     av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     path = path1; | 
					
						
							|  |  |  |     if (*path == '/') | 
					
						
							|  |  |  |         path++; | 
					
						
							| 
									
										
										
										
											2003-06-29 01:25:41 +00:00
										 |  |  |     if(!strcmp(path, rtp_c->stream->filename)) return rtp_c; | 
					
						
							|  |  |  |     for(s=0; s<rtp_c->stream->nb_streams; ++s) { | 
					
						
							|  |  |  |       snprintf(buf, sizeof(buf), "%s/streamid=%d", | 
					
						
							|  |  |  |         rtp_c->stream->filename, s); | 
					
						
							|  |  |  |       if(!strncmp(path, buf, sizeof(buf))) { | 
					
						
							|  |  |  |     // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
 | 
					
						
							|  |  |  |         return rtp_c; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-02-16 16:37:40 +02:00
										 |  |  |     len = strlen(path); | 
					
						
							|  |  |  |     if (len > 0 && path[len - 1] == '/' && | 
					
						
							|  |  |  |         !strncmp(path, rtp_c->stream->filename, len - 1)) | 
					
						
							|  |  |  |         return rtp_c; | 
					
						
							| 
									
										
										
										
											2003-06-29 01:25:41 +00:00
										 |  |  |     return NULL; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  | static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     HTTPContext *rtp_c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rtp_c = find_rtp_session_with_url(url, h->session_id); | 
					
						
							|  |  |  |     if (!rtp_c) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_SESSION); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     if (rtp_c->state != HTTPSTATE_SEND_DATA && | 
					
						
							|  |  |  |         rtp_c->state != HTTPSTATE_WAIT_FEED && | 
					
						
							|  |  |  |         rtp_c->state != HTTPSTATE_READY) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_STATE); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rtp_c->state = HTTPSTATE_SEND_DATA; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* now everything is OK, so we can send the connection parameters */ | 
					
						
							|  |  |  |     rtsp_reply_header(c, RTSP_STATUS_OK); | 
					
						
							|  |  |  |     /* session ID */ | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); | 
					
						
							|  |  |  |     avio_printf(c->pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  | static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     HTTPContext *rtp_c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rtp_c = find_rtp_session_with_url(url, h->session_id); | 
					
						
							|  |  |  |     if (!rtp_c) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_SESSION); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     if (rtp_c->state != HTTPSTATE_SEND_DATA && | 
					
						
							|  |  |  |         rtp_c->state != HTTPSTATE_WAIT_FEED) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_STATE); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     rtp_c->state = HTTPSTATE_READY; | 
					
						
							| 
									
										
										
										
											2003-07-11 22:30:12 +00:00
										 |  |  |     rtp_c->first_pts = AV_NOPTS_VALUE; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* now everything is OK, so we can send the connection parameters */ | 
					
						
							|  |  |  |     rtsp_reply_header(c, RTSP_STATUS_OK); | 
					
						
							|  |  |  |     /* session ID */ | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); | 
					
						
							|  |  |  |     avio_printf(c->pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  | static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     HTTPContext *rtp_c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rtp_c = find_rtp_session_with_url(url, h->session_id); | 
					
						
							|  |  |  |     if (!rtp_c) { | 
					
						
							|  |  |  |         rtsp_reply_error(c, RTSP_STATUS_SESSION); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* now everything is OK, so we can send the connection parameters */ | 
					
						
							|  |  |  |     rtsp_reply_header(c, RTSP_STATUS_OK); | 
					
						
							|  |  |  |     /* session ID */ | 
					
						
							| 
									
										
										
										
											2011-05-18 09:14:22 -04:00
										 |  |  |     avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); | 
					
						
							| 
									
										
										
										
											2011-03-14 20:39:02 +01:00
										 |  |  |     avio_printf(c->pb, "\r\n"); | 
					
						
							| 
									
										
										
										
											2011-05-18 09:14:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* abort the session */ | 
					
						
							|  |  |  |     close_connection(rtp_c); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************/ | 
					
						
							|  |  |  | /* RTP handling */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                                        FFStream *stream, const char *session_id, | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |                                        enum RTSPLowerTransport rtp_protocol) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     HTTPContext *c = NULL; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     const char *proto_str; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* XXX: should output a warning page when coming
 | 
					
						
							|  |  |  |        close to the connection limit */ | 
					
						
							|  |  |  |     if (nb_connections >= nb_max_connections) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* add a new connection */ | 
					
						
							|  |  |  |     c = av_mallocz(sizeof(HTTPContext)); | 
					
						
							|  |  |  |     if (!c) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->fd = -1; | 
					
						
							|  |  |  |     c->poll_entry = NULL; | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |     c->from_addr = *from_addr; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->buffer_size = IOBUFFER_INIT_SIZE; | 
					
						
							|  |  |  |     c->buffer = av_malloc(c->buffer_size); | 
					
						
							|  |  |  |     if (!c->buffer) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  |     nb_connections++; | 
					
						
							|  |  |  |     c->stream = stream; | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     av_strlcpy(c->session_id, session_id, sizeof(c->session_id)); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->state = HTTPSTATE_READY; | 
					
						
							|  |  |  |     c->is_packetized = 1; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     c->rtp_protocol = rtp_protocol; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* protocol is shown in statistics */ | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     switch(c->rtp_protocol) { | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         proto_str = "MCAST"; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     case RTSP_LOWER_TRANSPORT_UDP: | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         proto_str = "UDP"; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     case RTSP_LOWER_TRANSPORT_TCP: | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         proto_str = "TCP"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         proto_str = "???"; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol)); | 
					
						
							|  |  |  |     av_strlcat(c->protocol, proto_str, sizeof(c->protocol)); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |     current_bandwidth += stream->bandwidth; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->next = first_http_ctx; | 
					
						
							|  |  |  |     first_http_ctx = c; | 
					
						
							|  |  |  |     return c; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |  fail: | 
					
						
							|  |  |  |     if (c) { | 
					
						
							|  |  |  |         av_free(c->buffer); | 
					
						
							|  |  |  |         av_free(c); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* add a new RTP stream in an RTP connection (used in RTSP SETUP
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |    command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |    used. */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static int rtp_new_av_stream(HTTPContext *c, | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |                              int stream_index, struct sockaddr_in *dest_addr, | 
					
						
							|  |  |  |                              HTTPContext *rtsp_c) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     AVFormatContext *ctx; | 
					
						
							|  |  |  |     AVStream *st; | 
					
						
							|  |  |  |     char *ipaddr; | 
					
						
							| 
									
										
										
										
											2008-05-29 01:59:44 +00:00
										 |  |  |     URLContext *h = NULL; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     uint8_t *dummy_buf; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     int max_packet_size; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* now we can open the relevant output stream */ | 
					
						
							| 
									
										
										
										
											2009-02-08 08:27:26 +00:00
										 |  |  |     ctx = avformat_alloc_context(); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     if (!ctx) | 
					
						
							|  |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2010-01-01 12:58:03 +00:00
										 |  |  |     ctx->oformat = av_guess_format("rtp", NULL, NULL); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     st = av_mallocz(sizeof(AVStream)); | 
					
						
							|  |  |  |     if (!st) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  |     ctx->nb_streams = 1; | 
					
						
							| 
									
										
										
										
											2011-05-18 11:03:10 -04:00
										 |  |  |     ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams); | 
					
						
							|  |  |  |     if (!ctx->streams) | 
					
						
							|  |  |  |       goto fail; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     ctx->streams[0] = st; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |     if (!c->stream->feed || | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         c->stream->feed == c->stream) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         memcpy(st, c->stream->streams[stream_index], sizeof(AVStream)); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         memcpy(st, | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                c->stream->feed->streams[c->stream->feed_streams[stream_index]], | 
					
						
							|  |  |  |                sizeof(AVStream)); | 
					
						
							| 
									
										
										
										
											2007-04-24 13:28:38 +00:00
										 |  |  |     st->priv_data = NULL; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |     /* build destination RTP address */ | 
					
						
							|  |  |  |     ipaddr = inet_ntoa(dest_addr->sin_addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch(c->rtp_protocol) { | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     case RTSP_LOWER_TRANSPORT_UDP: | 
					
						
							|  |  |  |     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         /* RTP/UDP case */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |         /* XXX: also pass as parameter to function ? */ | 
					
						
							|  |  |  |         if (c->stream->is_multicast) { | 
					
						
							|  |  |  |             int ttl; | 
					
						
							|  |  |  |             ttl = c->stream->multicast_ttl; | 
					
						
							|  |  |  |             if (!ttl) | 
					
						
							|  |  |  |                 ttl = 16; | 
					
						
							|  |  |  |             snprintf(ctx->filename, sizeof(ctx->filename), | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                      "rtp://%s:%d?multicast=1&ttl=%d", | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                      ipaddr, ntohs(dest_addr->sin_port), ttl); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             snprintf(ctx->filename, sizeof(ctx->filename), | 
					
						
							|  |  |  |                      "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-15 16:42:09 +02:00
										 |  |  |         if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  |         c->rtp_handles[stream_index] = h; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         max_packet_size = url_get_max_packet_size(h); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     case RTSP_LOWER_TRANSPORT_TCP: | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |         /* RTP/TCP case */ | 
					
						
							|  |  |  |         c->rtsp_c = rtsp_c; | 
					
						
							|  |  |  |         max_packet_size = RTSP_TCP_MAX_PACKET_SIZE; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-23 02:16:00 +00:00
										 |  |  |     http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n", | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |              ipaddr, ntohs(dest_addr->sin_port), | 
					
						
							| 
									
										
										
										
											2003-07-17 10:31:23 +00:00
										 |  |  |              c->stream->filename, stream_index, c->protocol); | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* normally, no packets should be output here, but the packet size may be checked */ | 
					
						
							| 
									
										
										
										
											2011-03-17 08:19:54 +01:00
										 |  |  |     if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         /* XXX: close stream */ | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |     if (avformat_write_header(ctx, NULL) < 0) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     fail: | 
					
						
							|  |  |  |         if (h) | 
					
						
							|  |  |  |             url_close(h); | 
					
						
							|  |  |  |         av_free(ctx); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-03-17 08:16:07 +01:00
										 |  |  |     avio_close_dyn_buf(ctx->pb, &dummy_buf); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     av_free(dummy_buf); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     c->rtp_ctx[stream_index] = ctx; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************/ | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | /* avserver initialization */ | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-24 19:59:18 +00:00
										 |  |  | static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     AVStream *fst; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fst = av_mallocz(sizeof(AVStream)); | 
					
						
							|  |  |  |     if (!fst) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2010-05-24 19:59:18 +00:00
										 |  |  |     if (copy) { | 
					
						
							| 
									
										
										
										
											2011-06-18 13:40:48 +02:00
										 |  |  |         fst->codec = avcodec_alloc_context3(NULL); | 
					
						
							| 
									
										
										
										
											2010-05-24 19:59:18 +00:00
										 |  |  |         memcpy(fst->codec, codec, sizeof(AVCodecContext)); | 
					
						
							|  |  |  |         if (codec->extradata_size) { | 
					
						
							|  |  |  |             fst->codec->extradata = av_malloc(codec->extradata_size); | 
					
						
							|  |  |  |             memcpy(fst->codec->extradata, codec->extradata, | 
					
						
							|  |  |  |                 codec->extradata_size); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         /* live streams must use the actual feed's codec since it may be
 | 
					
						
							|  |  |  |          * updated later to carry extradata needed by the streams. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         fst->codec = codec; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     fst->priv_data = av_mallocz(sizeof(FeedData)); | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |     fst->index = stream->nb_streams; | 
					
						
							| 
									
										
										
										
											2005-01-03 02:42:02 +00:00
										 |  |  |     av_set_pts_info(fst, 33, 1, 90000); | 
					
						
							| 
									
										
										
										
											2011-02-16 14:53:08 +01:00
										 |  |  |     fst->sample_aspect_ratio = codec->sample_aspect_ratio; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     stream->streams[stream->nb_streams++] = fst; | 
					
						
							|  |  |  |     return fst; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | /* return the stream number in the feed */ | 
					
						
							| 
									
										
										
										
											2003-02-10 09:44:47 +00:00
										 |  |  | static int add_av_stream(FFStream *feed, AVStream *st) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     AVStream *fst; | 
					
						
							|  |  |  |     AVCodecContext *av, *av1; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |     av = st->codec; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     for(i=0;i<feed->nb_streams;i++) { | 
					
						
							|  |  |  |         st = feed->streams[i]; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |         av1 = st->codec; | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |         if (av1->codec_id == av->codec_id && | 
					
						
							|  |  |  |             av1->codec_type == av->codec_type && | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             av1->bit_rate == av->bit_rate) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             switch(av->codec_type) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |             case AVMEDIA_TYPE_AUDIO: | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 if (av1->channels == av->channels && | 
					
						
							|  |  |  |                     av1->sample_rate == av->sample_rate) | 
					
						
							| 
									
										
										
										
											2011-07-11 16:32:54 +02:00
										 |  |  |                     return i; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |             case AVMEDIA_TYPE_VIDEO: | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 if (av1->width == av->width && | 
					
						
							|  |  |  |                     av1->height == av->height && | 
					
						
							| 
									
										
										
										
											2005-04-30 21:43:59 +00:00
										 |  |  |                     av1->time_base.den == av->time_base.den && | 
					
						
							|  |  |  |                     av1->time_base.num == av->time_base.num && | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                     av1->gop_size == av->gop_size) | 
					
						
							| 
									
										
										
										
											2011-07-11 16:32:54 +02:00
										 |  |  |                     return i; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |             default: | 
					
						
							| 
									
										
										
										
											2007-07-02 07:43:23 +00:00
										 |  |  |                 abort(); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-24 19:59:18 +00:00
										 |  |  |     fst = add_av_stream1(feed, av, 0); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     if (!fst) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     return feed->nb_streams - 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-10 09:44:47 +00:00
										 |  |  | static void remove_stream(FFStream *stream) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     FFStream **ps; | 
					
						
							|  |  |  |     ps = &first_stream; | 
					
						
							|  |  |  |     while (*ps != NULL) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         if (*ps == stream) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             *ps = (*ps)->next; | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             ps = &(*ps)->next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  | /* specific mpeg4 handling : we extract the raw parameters */ | 
					
						
							| 
									
										
										
										
											2003-02-10 09:44:47 +00:00
										 |  |  | static void extract_mpeg4_header(AVFormatContext *infile) | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int mpeg4_count, i, size; | 
					
						
							|  |  |  |     AVPacket pkt; | 
					
						
							|  |  |  |     AVStream *st; | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |     const uint8_t *p; | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     mpeg4_count = 0; | 
					
						
							|  |  |  |     for(i=0;i<infile->nb_streams;i++) { | 
					
						
							|  |  |  |         st = infile->streams[i]; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |         if (st->codec->codec_id == CODEC_ID_MPEG4 && | 
					
						
							|  |  |  |             st->codec->extradata_size == 0) { | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  |             mpeg4_count++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!mpeg4_count) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-19 02:23:17 +00:00
										 |  |  |     printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename); | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  |     while (mpeg4_count > 0) { | 
					
						
							|  |  |  |         if (av_read_packet(infile, &pkt) < 0) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         st = infile->streams[pkt.stream_index]; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |         if (st->codec->codec_id == CODEC_ID_MPEG4 && | 
					
						
							|  |  |  |             st->codec->extradata_size == 0) { | 
					
						
							|  |  |  |             av_freep(&st->codec->extradata); | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  |             /* fill extradata with the header */ | 
					
						
							|  |  |  |             /* XXX: we make hard suppositions here ! */ | 
					
						
							|  |  |  |             p = pkt.data; | 
					
						
							|  |  |  |             while (p < pkt.data + pkt.size - 4) { | 
					
						
							|  |  |  |                 /* stop when vop header is found */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                 if (p[0] == 0x00 && p[1] == 0x00 && | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  |                     p[2] == 0x01 && p[3] == 0xb6) { | 
					
						
							|  |  |  |                     size = p - pkt.data; | 
					
						
							| 
									
										
										
										
											2007-03-12 14:17:26 +00:00
										 |  |  |                     //                    av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
 | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                     st->codec->extradata = av_malloc(size); | 
					
						
							|  |  |  |                     st->codec->extradata_size = size; | 
					
						
							|  |  |  |                     memcpy(st->codec->extradata, pkt.data, size); | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 p++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             mpeg4_count--; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         av_free_packet(&pkt); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | /* compute the needed AVStream for each file */ | 
					
						
							| 
									
										
										
										
											2003-02-10 09:44:47 +00:00
										 |  |  | static void build_file_streams(void) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     FFStream *stream, *stream_next; | 
					
						
							| 
									
										
										
										
											2008-05-24 02:34:19 +00:00
										 |  |  |     int i, ret; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* gather all streams */ | 
					
						
							|  |  |  |     for(stream = first_stream; stream != NULL; stream = stream_next) { | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |         AVFormatContext *infile = NULL; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         stream_next = stream->next; | 
					
						
							|  |  |  |         if (stream->stream_type == STREAM_TYPE_LIVE && | 
					
						
							|  |  |  |             !stream->feed) { | 
					
						
							|  |  |  |             /* the stream comes from a file */ | 
					
						
							|  |  |  |             /* try to open the file */ | 
					
						
							|  |  |  |             /* open stream */ | 
					
						
							| 
									
										
										
										
											2007-09-17 12:47:44 +00:00
										 |  |  |             if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) { | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                 /* specific case : if transport stream output to RTP,
 | 
					
						
							|  |  |  |                    we use a raw transport stream reader */ | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |                 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0); | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-20 01:05:51 +00:00
										 |  |  |             http_log("Opening file '%s'\n", stream->feed_filename); | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |             if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) { | 
					
						
							| 
									
										
										
										
											2009-03-20 01:05:51 +00:00
										 |  |  |                 http_log("Could not open '%s': %d\n", stream->feed_filename, ret); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 /* remove stream (no need to spend more time on it) */ | 
					
						
							|  |  |  |             fail: | 
					
						
							|  |  |  |                 remove_stream(stream); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 /* find all the AVStreams inside and reference them in
 | 
					
						
							|  |  |  |                    'stream' */ | 
					
						
							|  |  |  |                 if (av_find_stream_info(infile) < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-01 02:01:22 +00:00
										 |  |  |                     http_log("Could not find codec parameters from '%s'\n", | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                              stream->feed_filename); | 
					
						
							|  |  |  |                     av_close_input_file(infile); | 
					
						
							|  |  |  |                     goto fail; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2002-11-20 20:49:47 +00:00
										 |  |  |                 extract_mpeg4_header(infile); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 for(i=0;i<infile->nb_streams;i++) | 
					
						
							| 
									
										
										
										
											2010-05-24 19:59:18 +00:00
										 |  |  |                     add_av_stream1(stream, infile->streams[i]->codec, 1); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 av_close_input_file(infile); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | /* compute the needed AVStream for each feed */ | 
					
						
							| 
									
										
										
										
											2003-02-10 09:44:47 +00:00
										 |  |  | static void build_feed_streams(void) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     FFStream *stream, *feed; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     /* gather all streams */ | 
					
						
							|  |  |  |     for(stream = first_stream; stream != NULL; stream = stream->next) { | 
					
						
							|  |  |  |         feed = stream->feed; | 
					
						
							|  |  |  |         if (feed) { | 
					
						
							|  |  |  |             if (stream->is_feed) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 for(i=0;i<stream->nb_streams;i++) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                     stream->feed_streams[i] = i; | 
					
						
							| 
									
										
										
										
											2011-07-13 14:24:47 -04:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 /* we handle a stream coming from a feed */ | 
					
						
							|  |  |  |                 for(i=0;i<stream->nb_streams;i++) | 
					
						
							|  |  |  |                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* create feed files if needed */ | 
					
						
							|  |  |  |     for(feed = first_feed; feed != NULL; feed = feed->next_feed) { | 
					
						
							|  |  |  |         int fd; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-09 01:32:37 +02:00
										 |  |  |         if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) { | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |             /* See if it matches */ | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |             AVFormatContext *s = NULL; | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |             int matches = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |             if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) { | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                 /* Now see if it matches */ | 
					
						
							|  |  |  |                 if (s->nb_streams == feed->nb_streams) { | 
					
						
							|  |  |  |                     matches = 1; | 
					
						
							|  |  |  |                     for(i=0;i<s->nb_streams;i++) { | 
					
						
							|  |  |  |                         AVStream *sf, *ss; | 
					
						
							|  |  |  |                         sf = feed->streams[i]; | 
					
						
							|  |  |  |                         ss = s->streams[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (sf->index != ss->index || | 
					
						
							|  |  |  |                             sf->id != ss->id) { | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                             http_log("Index & Id do not match for stream %d (%s)\n", | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |                                    i, feed->feed_filename); | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                             matches = 0; | 
					
						
							|  |  |  |                         } else { | 
					
						
							|  |  |  |                             AVCodecContext *ccf, *ccs; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                             ccf = sf->codec; | 
					
						
							|  |  |  |                             ccs = ss->codec; | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  | #define CHECK_CODEC(x)  (ccf->x != ccs->x)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-24 20:24:39 +00:00
										 |  |  |                             if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) { | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                                 http_log("Codecs do not match for stream %d\n", i); | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                                 matches = 0; | 
					
						
							|  |  |  |                             } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) { | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                                 http_log("Codec bitrates do not match for stream %d\n", i); | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                                 matches = 0; | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                             } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) { | 
					
						
							| 
									
										
										
										
											2005-04-30 21:43:59 +00:00
										 |  |  |                                 if (CHECK_CODEC(time_base.den) || | 
					
						
							|  |  |  |                                     CHECK_CODEC(time_base.num) || | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                                     CHECK_CODEC(width) || | 
					
						
							|  |  |  |                                     CHECK_CODEC(height)) { | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                                     http_log("Codec width, height and framerate do not match for stream %d\n", i); | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                                     matches = 0; | 
					
						
							|  |  |  |                                 } | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                             } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) { | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                                 if (CHECK_CODEC(sample_rate) || | 
					
						
							|  |  |  |                                     CHECK_CODEC(channels) || | 
					
						
							|  |  |  |                                     CHECK_CODEC(frame_size)) { | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                                     http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i); | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                                     matches = 0; | 
					
						
							|  |  |  |                                 } | 
					
						
							|  |  |  |                             } else { | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                                 http_log("Unknown codec type\n"); | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                                 matches = 0; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                         if (!matches) | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                             break; | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 } else | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                     http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n", | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                         feed->feed_filename, s->nb_streams, feed->nb_streams); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 av_close_input_file(s); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             } else | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                 http_log("Deleting feed file '%s' as it appears to be corrupt\n", | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                         feed->feed_filename); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |             if (!matches) { | 
					
						
							|  |  |  |                 if (feed->readonly) { | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                     http_log("Unable to delete feed file '%s' as it is marked readonly\n", | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |                         feed->feed_filename); | 
					
						
							|  |  |  |                     exit(1); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |                 unlink(feed->feed_filename); | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-07-28 04:19:46 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-04-09 01:32:37 +02:00
										 |  |  |         if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) { | 
					
						
							| 
									
										
										
										
											2009-01-09 20:03:53 +00:00
										 |  |  |             AVFormatContext s1 = {0}, *s = &s1; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |             if (feed->readonly) { | 
					
						
							| 
									
										
										
										
											2008-06-25 19:00:06 +00:00
										 |  |  |                 http_log("Unable to create feed file '%s' as it is marked readonly\n", | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |                     feed->feed_filename); | 
					
						
							|  |  |  |                 exit(1); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             /* only write the header of the ffm file */ | 
					
						
							| 
									
										
										
										
											2011-04-15 16:42:09 +02:00
										 |  |  |             if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:29:59 +00:00
										 |  |  |                 http_log("Could not open output feed file '%s'\n", | 
					
						
							|  |  |  |                          feed->feed_filename); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 exit(1); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-20 16:33:46 +00:00
										 |  |  |             s->oformat = feed->fmt; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             s->nb_streams = feed->nb_streams; | 
					
						
							| 
									
										
										
										
											2011-05-18 11:03:10 -04:00
										 |  |  |             s->streams = feed->streams; | 
					
						
							| 
									
										
										
										
											2011-06-09 10:58:23 +02:00
										 |  |  |             if (avformat_write_header(s, NULL) < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:29:59 +00:00
										 |  |  |                 http_log("Container doesn't supports the required parameters\n"); | 
					
						
							| 
									
										
										
										
											2007-02-24 02:24:42 +00:00
										 |  |  |                 exit(1); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-20 16:33:46 +00:00
										 |  |  |             /* XXX: need better api */ | 
					
						
							|  |  |  |             av_freep(&s->priv_data); | 
					
						
							| 
									
										
										
										
											2011-02-21 22:45:20 +01:00
										 |  |  |             avio_close(s->pb); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         /* get feed size and write index */ | 
					
						
							|  |  |  |         fd = open(feed->feed_filename, O_RDONLY); | 
					
						
							|  |  |  |         if (fd < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:29:59 +00:00
										 |  |  |             http_log("Could not open output feed file '%s'\n", | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                     feed->feed_filename); | 
					
						
							|  |  |  |             exit(1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 06:52:55 +00:00
										 |  |  |         feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         feed->feed_size = lseek(fd, 0, SEEK_END); | 
					
						
							|  |  |  |         /* ensure that we do not wrap before the end of file */ | 
					
						
							| 
									
										
										
										
											2005-11-13 03:26:43 +00:00
										 |  |  |         if (feed->feed_max_size && feed->feed_max_size < feed->feed_size) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             feed->feed_max_size = feed->feed_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         close(fd); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  | /* compute the bandwidth used by each stream */ | 
					
						
							|  |  |  | static void compute_bandwidth(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:38:49 +00:00
										 |  |  |     unsigned bandwidth; | 
					
						
							|  |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |     FFStream *stream; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |     for(stream = first_stream; stream != NULL; stream = stream->next) { | 
					
						
							|  |  |  |         bandwidth = 0; | 
					
						
							|  |  |  |         for(i=0;i<stream->nb_streams;i++) { | 
					
						
							|  |  |  |             AVStream *st = stream->streams[i]; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |             switch(st->codec->codec_type) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |             case AVMEDIA_TYPE_AUDIO: | 
					
						
							|  |  |  |             case AVMEDIA_TYPE_VIDEO: | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |                 bandwidth += st->codec->bit_rate; | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         stream->bandwidth = (bandwidth + 999) / 1000; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | /* add a codec and set the default parameters */ | 
					
						
							| 
									
										
										
										
											2003-02-10 09:44:47 +00:00
										 |  |  | static void add_codec(FFStream *stream, AVCodecContext *av) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     AVStream *st; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* compute default parameters */ | 
					
						
							|  |  |  |     switch(av->codec_type) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |     case AVMEDIA_TYPE_AUDIO: | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         if (av->bit_rate == 0) | 
					
						
							|  |  |  |             av->bit_rate = 64000; | 
					
						
							|  |  |  |         if (av->sample_rate == 0) | 
					
						
							|  |  |  |             av->sample_rate = 22050; | 
					
						
							|  |  |  |         if (av->channels == 0) | 
					
						
							|  |  |  |             av->channels = 1; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |     case AVMEDIA_TYPE_VIDEO: | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         if (av->bit_rate == 0) | 
					
						
							|  |  |  |             av->bit_rate = 64000; | 
					
						
							| 
									
										
										
										
											2005-04-30 21:43:59 +00:00
										 |  |  |         if (av->time_base.num == 0){ | 
					
						
							|  |  |  |             av->time_base.den = 5; | 
					
						
							|  |  |  |             av->time_base.num = 1; | 
					
						
							| 
									
										
										
										
											2003-03-12 15:16:19 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         if (av->width == 0 || av->height == 0) { | 
					
						
							|  |  |  |             av->width = 160; | 
					
						
							|  |  |  |             av->height = 128; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-05-09 02:33:27 +00:00
										 |  |  |         /* Bitrate tolerance is less for streaming */ | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         if (av->bit_rate_tolerance == 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 02:19:46 +00:00
										 |  |  |             av->bit_rate_tolerance = FFMAX(av->bit_rate / 4, | 
					
						
							|  |  |  |                       (int64_t)av->bit_rate*av->time_base.num/av->time_base.den); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         if (av->qmin == 0) | 
					
						
							|  |  |  |             av->qmin = 3; | 
					
						
							|  |  |  |         if (av->qmax == 0) | 
					
						
							|  |  |  |             av->qmax = 31; | 
					
						
							|  |  |  |         if (av->max_qdiff == 0) | 
					
						
							|  |  |  |             av->max_qdiff = 3; | 
					
						
							| 
									
										
										
										
											2002-05-09 02:33:27 +00:00
										 |  |  |         av->qcompress = 0.5; | 
					
						
							|  |  |  |         av->qblur = 0.5; | 
					
						
							| 
									
										
										
										
											2002-03-19 04:31:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         if (!av->nsse_weight) | 
					
						
							| 
									
										
										
										
											2005-05-06 03:21:04 +00:00
										 |  |  |             av->nsse_weight = 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         av->frame_skip_cmp = FF_CMP_DCTMAX; | 
					
						
							| 
									
										
										
										
											2010-05-18 11:45:09 +00:00
										 |  |  |         if (!av->me_method) | 
					
						
							| 
									
										
										
										
											2010-05-18 11:46:23 +00:00
										 |  |  |             av->me_method = ME_EPZS; | 
					
						
							| 
									
										
										
										
											2005-05-06 03:21:04 +00:00
										 |  |  |         av->rc_buffer_aggressivity = 1.0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-09-12 02:31:11 +00:00
										 |  |  |         if (!av->rc_eq) | 
					
						
							|  |  |  |             av->rc_eq = "tex^qComp"; | 
					
						
							|  |  |  |         if (!av->i_quant_factor) | 
					
						
							| 
									
										
										
										
											2002-09-19 20:22:39 +00:00
										 |  |  |             av->i_quant_factor = -0.8; | 
					
						
							| 
									
										
										
										
											2002-09-12 02:31:11 +00:00
										 |  |  |         if (!av->b_quant_factor) | 
					
						
							|  |  |  |             av->b_quant_factor = 1.25; | 
					
						
							|  |  |  |         if (!av->b_quant_offset) | 
					
						
							|  |  |  |             av->b_quant_offset = 1.25; | 
					
						
							| 
									
										
										
										
											2002-10-30 02:15:07 +00:00
										 |  |  |         if (!av->rc_max_rate) | 
					
						
							|  |  |  |             av->rc_max_rate = av->bit_rate * 2; | 
					
						
							| 
									
										
										
										
											2002-09-12 02:31:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-05-06 03:21:04 +00:00
										 |  |  |         if (av->rc_max_rate && !av->rc_buffer_size) { | 
					
						
							|  |  |  |             av->rc_buffer_size = av->rc_max_rate; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |     default: | 
					
						
							| 
									
										
										
										
											2007-07-02 07:43:23 +00:00
										 |  |  |         abort(); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     st = av_mallocz(sizeof(AVStream)); | 
					
						
							|  |  |  |     if (!st) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-06-18 13:40:48 +02:00
										 |  |  |     st->codec = avcodec_alloc_context3(NULL); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     stream->streams[stream->nb_streams++] = st; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |     memcpy(st->codec, av, sizeof(AVCodecContext)); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 12:02:35 +00:00
										 |  |  | static enum CodecID opt_audio_codec(const char *arg) | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-12 18:47:58 +00:00
										 |  |  |     AVCodec *p= avcodec_find_encoder_by_name(arg); | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |     if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO) | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |         return CODEC_ID_NONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return p->id; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 12:02:35 +00:00
										 |  |  | static enum CodecID opt_video_codec(const char *arg) | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-12 18:47:58 +00:00
										 |  |  |     AVCodec *p= avcodec_find_encoder_by_name(arg); | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |     if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO) | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |         return CODEC_ID_NONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return p->id; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | /* simplistic plugin support */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-13 23:44:16 +00:00
										 |  |  | #if HAVE_DLOPEN
 | 
					
						
							| 
									
										
										
										
											2006-06-18 11:33:14 +00:00
										 |  |  | static void load_module(const char *filename) | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     void *dll; | 
					
						
							|  |  |  |     void (*init_func)(void); | 
					
						
							|  |  |  |     dll = dlopen(filename, RTLD_NOW); | 
					
						
							|  |  |  |     if (!dll) { | 
					
						
							|  |  |  |         fprintf(stderr, "Could not load module '%s' - %s\n", | 
					
						
							|  |  |  |                 filename, dlerror()); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     init_func = dlsym(dll, "avserver_module_init"); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     if (!init_func) { | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         fprintf(stderr, | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |                 "%s: init function 'avserver_module_init()' not found\n", | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |                 filename); | 
					
						
							|  |  |  |         dlclose(dll); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     init_func(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2002-11-30 17:18:59 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | static int avserver_opt_default(const char *opt, const char *arg, | 
					
						
							| 
									
										
										
										
											2008-06-09 00:25:33 +00:00
										 |  |  |                        AVCodecContext *avctx, int type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-12-19 22:29:30 +00:00
										 |  |  |     int ret = 0; | 
					
						
							| 
									
										
										
										
											2011-05-22 13:25:19 +02:00
										 |  |  |     const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0); | 
					
						
							| 
									
										
										
										
											2008-12-19 22:33:15 +00:00
										 |  |  |     if(o) | 
					
						
							| 
									
										
										
										
											2008-12-19 22:29:30 +00:00
										 |  |  |         ret = av_set_string3(avctx, opt, arg, 1, NULL); | 
					
						
							|  |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2008-06-09 00:25:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | static int avserver_opt_preset(const char *arg, | 
					
						
							| 
									
										
										
										
											2010-06-08 09:55:30 +00:00
										 |  |  |                        AVCodecContext *avctx, int type, | 
					
						
							|  |  |  |                        enum CodecID *audio_id, enum CodecID *video_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FILE *f=NULL; | 
					
						
							|  |  |  |     char filename[1000], tmp[1000], tmp2[1000], line[1000]; | 
					
						
							| 
									
										
										
										
											2010-11-04 23:07:04 +00:00
										 |  |  |     int ret = 0; | 
					
						
							|  |  |  |     AVCodec *codec = avcodec_find_encoder(avctx->codec_id); | 
					
						
							| 
									
										
										
										
											2010-06-08 09:55:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-04 23:07:04 +00:00
										 |  |  |     if (!(f = get_preset_file(filename, sizeof(filename), arg, 0, | 
					
						
							|  |  |  |                               codec ? codec->name : NULL))) { | 
					
						
							| 
									
										
										
										
											2010-06-08 09:55:30 +00:00
										 |  |  |         fprintf(stderr, "File for preset '%s' not found\n", arg); | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while(!feof(f)){ | 
					
						
							|  |  |  |         int e= fscanf(f, "%999[^\n]\n", line) - 1; | 
					
						
							|  |  |  |         if(line[0] == '#' && !e) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; | 
					
						
							|  |  |  |         if(e){ | 
					
						
							|  |  |  |             fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line); | 
					
						
							|  |  |  |             ret = 1; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if(!strcmp(tmp, "acodec")){ | 
					
						
							|  |  |  |             *audio_id = opt_audio_codec(tmp2); | 
					
						
							|  |  |  |         }else if(!strcmp(tmp, "vcodec")){ | 
					
						
							|  |  |  |             *video_id = opt_video_codec(tmp2); | 
					
						
							|  |  |  |         }else if(!strcmp(tmp, "scodec")){ | 
					
						
							|  |  |  |             /* opt_subtitle_codec(tmp2); */ | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |         }else if(avserver_opt_default(tmp, tmp2, avctx, type) < 0){ | 
					
						
							| 
									
										
										
										
											2010-06-08 09:55:30 +00:00
										 |  |  |             fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2); | 
					
						
							|  |  |  |             ret = 1; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fclose(f); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  | static AVOutputFormat *avserver_guess_format(const char *short_name, const char *filename, | 
					
						
							| 
									
										
										
										
											2009-12-31 14:12:58 +00:00
										 |  |  |                                              const char *mime_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-01-01 12:58:03 +00:00
										 |  |  |     AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type); | 
					
						
							| 
									
										
										
										
											2009-12-31 14:12:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (fmt) { | 
					
						
							|  |  |  |         AVOutputFormat *stream_fmt; | 
					
						
							|  |  |  |         char stream_format_name[64]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name); | 
					
						
							| 
									
										
										
										
											2010-01-01 12:58:03 +00:00
										 |  |  |         stream_fmt = av_guess_format(stream_format_name, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2009-12-31 14:12:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (stream_fmt) | 
					
						
							|  |  |  |             fmt = stream_fmt; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return fmt; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  | static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     va_list vl; | 
					
						
							|  |  |  |     va_start(vl, fmt); | 
					
						
							|  |  |  |     fprintf(stderr, "%s:%d: ", filename, line_num); | 
					
						
							|  |  |  |     vfprintf(stderr, fmt, vl); | 
					
						
							|  |  |  |     va_end(vl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     (*errors)++; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-10 09:44:47 +00:00
										 |  |  | static int parse_ffconfig(const char *filename) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     FILE *f; | 
					
						
							|  |  |  |     char line[1024]; | 
					
						
							|  |  |  |     char cmd[64]; | 
					
						
							|  |  |  |     char arg[1024]; | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  |     int val, errors, line_num; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     FFStream **last_stream, *stream, *redirect; | 
					
						
							| 
									
										
										
										
											2009-03-20 00:55:00 +00:00
										 |  |  |     FFStream **last_feed, *feed, *s; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     AVCodecContext audio_enc, video_enc; | 
					
						
							| 
									
										
										
										
											2008-12-30 12:02:35 +00:00
										 |  |  |     enum CodecID audio_id, video_id; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     f = fopen(filename, "r"); | 
					
						
							|  |  |  |     if (!f) { | 
					
						
							|  |  |  |         perror(filename); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     errors = 0; | 
					
						
							|  |  |  |     line_num = 0; | 
					
						
							|  |  |  |     first_stream = NULL; | 
					
						
							|  |  |  |     last_stream = &first_stream; | 
					
						
							|  |  |  |     first_feed = NULL; | 
					
						
							|  |  |  |     last_feed = &first_feed; | 
					
						
							|  |  |  |     stream = NULL; | 
					
						
							|  |  |  |     feed = NULL; | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     redirect = NULL; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     audio_id = CODEC_ID_NONE; | 
					
						
							|  |  |  |     video_id = CODEC_ID_NONE; | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     for(;;) { | 
					
						
							|  |  |  |         if (fgets(line, sizeof(line), f) == NULL) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         line_num++; | 
					
						
							|  |  |  |         p = line; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         while (isspace(*p)) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             p++; | 
					
						
							|  |  |  |         if (*p == '\0' || *p == '#') | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         get_arg(cmd, sizeof(cmd), &p); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         if (!strcasecmp(cmd, "Port")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-04-22 18:06:08 +00:00
										 |  |  |             val = atoi(arg); | 
					
						
							|  |  |  |             if (val < 1 || val > 65536) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Invalid_port: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2007-04-22 18:06:08 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             my_http_addr.sin_port = htons(val); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "BindAddress")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-04-25 21:05:47 +00:00
										 |  |  |             if (resolve_host(&my_http_addr.sin_addr, arg) != 0) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("%s:%d: Invalid host/IP address: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "NoDaemon")) { | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |             avserver_daemon = 0; | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "RTSPPort")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-04-22 18:06:08 +00:00
										 |  |  |             val = atoi(arg); | 
					
						
							|  |  |  |             if (val < 1 || val > 65536) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("%s:%d: Invalid port: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2007-04-22 18:06:08 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             my_rtsp_addr.sin_port = htons(atoi(arg)); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "RTSPBindAddress")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-04-25 21:05:47 +00:00
										 |  |  |             if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Invalid host/IP address: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-09-03 18:16:34 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "MaxHTTPConnections")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             val = atoi(arg); | 
					
						
							|  |  |  |             if (val < 1 || val > 65536) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Invalid MaxHTTPConnections: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2008-09-03 18:16:34 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             nb_max_http_connections = val; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "MaxClients")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             val = atoi(arg); | 
					
						
							| 
									
										
										
										
											2008-09-03 18:16:34 +00:00
										 |  |  |             if (val < 1 || val > nb_max_http_connections) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Invalid MaxClients: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 nb_max_connections = val; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "MaxBandwidth")) { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:26:24 +00:00
										 |  |  |             int64_t llval; | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2008-06-21 03:26:24 +00:00
										 |  |  |             llval = atoll(arg); | 
					
						
							|  |  |  |             if (llval < 10 || llval > 10000000) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Invalid MaxBandwidth: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             } else | 
					
						
							| 
									
										
										
										
											2008-06-21 03:26:24 +00:00
										 |  |  |                 max_bandwidth = llval; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "CustomLog")) { | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |             if (!avserver_debug) | 
					
						
							| 
									
										
										
										
											2008-06-21 03:34:18 +00:00
										 |  |  |                 get_arg(logfilename, sizeof(logfilename), &p); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "<Feed")) { | 
					
						
							|  |  |  |             /*********************************************/ | 
					
						
							|  |  |  |             /* Feed related options */ | 
					
						
							|  |  |  |             char *q; | 
					
						
							|  |  |  |             if (stream || feed) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Already in a tag\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 feed = av_mallocz(sizeof(FFStream)); | 
					
						
							|  |  |  |                 get_arg(feed->filename, sizeof(feed->filename), &p); | 
					
						
							|  |  |  |                 q = strrchr(feed->filename, '>'); | 
					
						
							|  |  |  |                 if (*q) | 
					
						
							|  |  |  |                     *q = '\0'; | 
					
						
							| 
									
										
										
										
											2009-03-20 00:55:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 for (s = first_feed; s; s = s->next) { | 
					
						
							|  |  |  |                     if (!strcmp(feed->filename, s->filename)) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                         ERROR("Feed '%s' already registered\n", s->filename); | 
					
						
							| 
									
										
										
										
											2009-03-20 00:55:00 +00:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-01 12:58:03 +00:00
										 |  |  |                 feed->fmt = av_guess_format("ffm", NULL, NULL); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 /* defaut feed file */ | 
					
						
							|  |  |  |                 snprintf(feed->feed_filename, sizeof(feed->feed_filename), | 
					
						
							|  |  |  |                          "/tmp/%s.ffm", feed->filename); | 
					
						
							|  |  |  |                 feed->feed_max_size = 5 * 1024 * 1024; | 
					
						
							|  |  |  |                 feed->is_feed = 1; | 
					
						
							|  |  |  |                 feed->feed = feed; /* self feeding :-) */ | 
					
						
							| 
									
										
										
										
											2009-03-20 00:55:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 /* add in stream list */ | 
					
						
							|  |  |  |                 *last_stream = feed; | 
					
						
							|  |  |  |                 last_stream = &feed->next; | 
					
						
							|  |  |  |                 /* add in feed list */ | 
					
						
							|  |  |  |                 *last_feed = feed; | 
					
						
							|  |  |  |                 last_feed = &feed->next_feed; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "Launch")) { | 
					
						
							|  |  |  |             if (feed) { | 
					
						
							|  |  |  |                 int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-01 00:19:44 +00:00
										 |  |  |                 feed->child_argv = av_mallocz(64 * sizeof(char *)); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-13 01:45:13 +00:00
										 |  |  |                 for (i = 0; i < 62; i++) { | 
					
						
							| 
									
										
										
										
											2007-04-22 18:01:29 +00:00
										 |  |  |                     get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |                     if (!arg[0]) | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-22 18:01:29 +00:00
										 |  |  |                     feed->child_argv[i] = av_strdup(arg); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-22 01:10:11 +00:00
										 |  |  |                 snprintf(feed->child_argv[i], 30+strlen(feed->filename), | 
					
						
							|  |  |  |                     "http://%s:%d/%s", | 
					
						
							|  |  |  |                         (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" : | 
					
						
							|  |  |  |                     inet_ntoa(my_http_addr.sin_addr), | 
					
						
							|  |  |  |                     ntohs(my_http_addr.sin_port), feed->filename); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "ReadOnlyFile")) { | 
					
						
							|  |  |  |             if (feed) { | 
					
						
							|  |  |  |                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p); | 
					
						
							|  |  |  |                 feed->readonly = 1; | 
					
						
							|  |  |  |             } else if (stream) { | 
					
						
							|  |  |  |                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "File")) { | 
					
						
							|  |  |  |             if (feed) { | 
					
						
							|  |  |  |                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             } else if (stream) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p); | 
					
						
							| 
									
										
										
										
											2009-03-21 10:28:49 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "Truncate")) { | 
					
						
							|  |  |  |             if (feed) { | 
					
						
							|  |  |  |                 get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |                 feed->truncate = strtod(arg, NULL); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "FileMaxSize")) { | 
					
						
							|  |  |  |             if (feed) { | 
					
						
							| 
									
										
										
										
											2008-02-02 00:54:37 +00:00
										 |  |  |                 char *p1; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 double fsize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |                 p1 = arg; | 
					
						
							| 
									
										
										
										
											2008-02-02 00:54:37 +00:00
										 |  |  |                 fsize = strtod(p1, &p1); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 switch(toupper(*p1)) { | 
					
						
							|  |  |  |                 case 'K': | 
					
						
							|  |  |  |                     fsize *= 1024; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 case 'M': | 
					
						
							|  |  |  |                     fsize *= 1024 * 1024; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 case 'G': | 
					
						
							|  |  |  |                     fsize *= 1024 * 1024 * 1024; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  |                 feed->feed_max_size = (int64_t)fsize; | 
					
						
							| 
									
										
										
										
											2009-03-21 10:32:43 +00:00
										 |  |  |                 if (feed->feed_max_size < FFM_PACKET_SIZE*4) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4); | 
					
						
							| 
									
										
										
										
											2009-03-21 10:32:43 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "</Feed>")) { | 
					
						
							|  |  |  |             if (!feed) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("No corresponding <Feed> for </Feed>\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             feed = NULL; | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "<Stream")) { | 
					
						
							|  |  |  |             /*********************************************/ | 
					
						
							|  |  |  |             /* Stream related options */ | 
					
						
							|  |  |  |             char *q; | 
					
						
							|  |  |  |             if (stream || feed) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Already in a tag\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2009-03-20 00:55:00 +00:00
										 |  |  |                 FFStream *s; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 stream = av_mallocz(sizeof(FFStream)); | 
					
						
							|  |  |  |                 get_arg(stream->filename, sizeof(stream->filename), &p); | 
					
						
							|  |  |  |                 q = strrchr(stream->filename, '>'); | 
					
						
							|  |  |  |                 if (*q) | 
					
						
							|  |  |  |                     *q = '\0'; | 
					
						
							| 
									
										
										
										
											2009-03-20 00:55:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 for (s = first_stream; s; s = s->next) { | 
					
						
							|  |  |  |                     if (!strcmp(stream->filename, s->filename)) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                         ERROR("Stream '%s' already registered\n", s->filename); | 
					
						
							| 
									
										
										
										
											2009-03-20 00:55:00 +00:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |                 stream->fmt = avserver_guess_format(NULL, stream->filename, NULL); | 
					
						
							| 
									
										
										
										
											2010-03-31 21:02:34 +00:00
										 |  |  |                 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO); | 
					
						
							|  |  |  |                 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 audio_id = CODEC_ID_NONE; | 
					
						
							|  |  |  |                 video_id = CODEC_ID_NONE; | 
					
						
							|  |  |  |                 if (stream->fmt) { | 
					
						
							|  |  |  |                     audio_id = stream->fmt->audio_codec; | 
					
						
							|  |  |  |                     video_id = stream->fmt->video_codec; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2009-03-20 00:55:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 *last_stream = stream; | 
					
						
							|  |  |  |                 last_stream = &stream->next; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "Feed")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 FFStream *sfeed; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 sfeed = first_feed; | 
					
						
							|  |  |  |                 while (sfeed != NULL) { | 
					
						
							|  |  |  |                     if (!strcmp(sfeed->filename, arg)) | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     sfeed = sfeed->next_feed; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 if (!sfeed) | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("feed '%s' not defined\n", arg); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 else | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                     stream->feed = sfeed; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "Format")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2008-05-29 02:11:46 +00:00
										 |  |  |             if (stream) { | 
					
						
							| 
									
										
										
										
											2008-06-24 02:00:54 +00:00
										 |  |  |                 if (!strcmp(arg, "status")) { | 
					
						
							|  |  |  |                     stream->stream_type = STREAM_TYPE_STATUS; | 
					
						
							|  |  |  |                     stream->fmt = NULL; | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     stream->stream_type = STREAM_TYPE_LIVE; | 
					
						
							|  |  |  |                     /* jpeg cannot be used here, so use single frame jpeg */ | 
					
						
							|  |  |  |                     if (!strcmp(arg, "jpeg")) | 
					
						
							|  |  |  |                         strcpy(arg, "mjpeg"); | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |                     stream->fmt = avserver_guess_format(arg, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2008-06-24 02:00:54 +00:00
										 |  |  |                     if (!stream->fmt) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                         ERROR("Unknown Format: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2008-06-24 02:00:54 +00:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (stream->fmt) { | 
					
						
							|  |  |  |                     audio_id = stream->fmt->audio_codec; | 
					
						
							|  |  |  |                     video_id = stream->fmt->video_codec; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2008-05-29 02:11:46 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2003-11-10 19:02:56 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "InputFormat")) { | 
					
						
							| 
									
										
										
										
											2007-04-22 17:48:23 +00:00
										 |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2008-10-25 00:49:56 +00:00
										 |  |  |             if (stream) { | 
					
						
							| 
									
										
										
										
											2008-10-25 00:50:23 +00:00
										 |  |  |                 stream->ifmt = av_find_input_format(arg); | 
					
						
							|  |  |  |                 if (!stream->ifmt) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("Unknown input format: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2008-10-25 00:50:23 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2008-10-25 00:49:56 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "FaviconURL")) { | 
					
						
							|  |  |  |             if (stream && stream->stream_type == STREAM_TYPE_STATUS) { | 
					
						
							|  |  |  |                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p); | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("FaviconURL only permitted for status streams\n"); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "Author")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |                 get_arg(stream->author, sizeof(stream->author), &p); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "Comment")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |                 get_arg(stream->comment, sizeof(stream->comment), &p); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "Copyright")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |                 get_arg(stream->copyright, sizeof(stream->copyright), &p); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "Title")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-06-05 02:17:06 +00:00
										 |  |  |                 get_arg(stream->title, sizeof(stream->title), &p); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "Preroll")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |                 stream->prebuffer = atof(arg) * 1000; | 
					
						
							| 
									
										
										
										
											2002-05-17 01:53:28 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "StartSendOnKey")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-05-17 01:53:28 +00:00
										 |  |  |                 stream->send_on_key = 1; | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "AudioCodec")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             audio_id = opt_audio_codec(arg); | 
					
						
							|  |  |  |             if (audio_id == CODEC_ID_NONE) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Unknown AudioCodec: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "VideoCodec")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             video_id = opt_video_codec(arg); | 
					
						
							|  |  |  |             if (video_id == CODEC_ID_NONE) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Unknown VideoCodec: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2002-05-09 01:11:08 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-24 01:18:19 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "MaxTime")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |                 stream->max_time = atof(arg) * 1000; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "AudioBitRate")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2010-06-02 07:09:44 +00:00
										 |  |  |                 audio_enc.bit_rate = lrintf(atof(arg) * 1000); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "AudioChannels")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 audio_enc.channels = atoi(arg); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "AudioSampleRate")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 audio_enc.sample_rate = atoi(arg); | 
					
						
							| 
									
										
										
										
											2005-12-22 01:10:11 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "AudioQuality")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2002-09-01 18:07:56 +00:00
										 |  |  |             if (stream) { | 
					
						
							| 
									
										
										
										
											2002-12-04 10:04:03 +00:00
										 |  |  | //                audio_enc.quality = atof(arg) * 1000;
 | 
					
						
							| 
									
										
										
										
											2002-09-01 18:07:56 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-10-30 02:15:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "VideoBitRateRange")) { | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 int minrate, maxrate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) { | 
					
						
							|  |  |  |                     video_enc.rc_min_rate = minrate * 1000; | 
					
						
							|  |  |  |                     video_enc.rc_max_rate = maxrate * 1000; | 
					
						
							|  |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2002-10-30 02:15:07 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2005-05-06 03:21:04 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "Debug")) { | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |                 video_enc.debug = strtol(arg,0,0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "Strict")) { | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |                 video_enc.strict_std_compliance = atoi(arg); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2004-02-05 17:47:24 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "VideoBufferSize")) { | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2005-05-06 03:21:04 +00:00
										 |  |  |                 video_enc.rc_buffer_size = atoi(arg) * 8*1024; | 
					
						
							| 
									
										
										
										
											2004-02-05 17:47:24 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-10-30 02:15:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) { | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |                 video_enc.bit_rate_tolerance = atoi(arg) * 1000; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "VideoBitRate")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 video_enc.bit_rate = atoi(arg) * 1000; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "VideoSize")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							| 
									
										
										
										
											2010-07-26 23:12:28 +00:00
										 |  |  |                 av_parse_video_size(&video_enc.width, &video_enc.height, arg); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 if ((video_enc.width % 16) != 0 || | 
					
						
							|  |  |  |                     (video_enc.height % 16) != 0) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("Image size must be a multiple of 16\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "VideoFrameRate")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							| 
									
										
										
										
											2008-05-29 17:24:22 +00:00
										 |  |  |                 AVRational frame_rate; | 
					
						
							| 
									
										
										
										
											2010-07-26 23:12:28 +00:00
										 |  |  |                 if (av_parse_video_rate(&frame_rate, arg) < 0) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("Incorrect frame rate: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2008-05-29 17:24:22 +00:00
										 |  |  |                 } else { | 
					
						
							|  |  |  |                     video_enc.time_base.num = frame_rate.den; | 
					
						
							|  |  |  |                     video_enc.time_base.den = frame_rate.num; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "VideoGopSize")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 video_enc.gop_size = atoi(arg); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "VideoIntraOnly")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 video_enc.gop_size = 1; | 
					
						
							| 
									
										
										
										
											2002-05-09 07:43:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "VideoHighQuality")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2003-07-29 02:09:12 +00:00
										 |  |  |                 video_enc.mb_decision = FF_MB_DECISION_BITS; | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "Video4MotionVector")) { | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							| 
									
										
										
										
											2003-07-29 02:09:12 +00:00
										 |  |  |                 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
 | 
					
						
							| 
									
										
										
										
											2003-04-09 02:16:01 +00:00
										 |  |  |                 video_enc.flags |= CODEC_FLAG_4MV; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-06-09 00:25:33 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "AVOptionVideo") || | 
					
						
							|  |  |  |                    !strcasecmp(cmd, "AVOptionAudio")) { | 
					
						
							|  |  |  |             char arg2[1024]; | 
					
						
							|  |  |  |             AVCodecContext *avctx; | 
					
						
							|  |  |  |             int type; | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             get_arg(arg2, sizeof(arg2), &p); | 
					
						
							|  |  |  |             if (!strcasecmp(cmd, "AVOptionVideo")) { | 
					
						
							|  |  |  |                 avctx = &video_enc; | 
					
						
							|  |  |  |                 type = AV_OPT_FLAG_VIDEO_PARAM; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 avctx = &audio_enc; | 
					
						
							|  |  |  |                 type = AV_OPT_FLAG_AUDIO_PARAM; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |             if (avserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("AVOption error: %s %s\n", arg, arg2); | 
					
						
							| 
									
										
										
										
											2008-06-09 00:25:33 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-06-08 09:55:30 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "AVPresetVideo") || | 
					
						
							|  |  |  |                    !strcasecmp(cmd, "AVPresetAudio")) { | 
					
						
							|  |  |  |             AVCodecContext *avctx; | 
					
						
							|  |  |  |             int type; | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             if (!strcasecmp(cmd, "AVPresetVideo")) { | 
					
						
							|  |  |  |                 avctx = &video_enc; | 
					
						
							|  |  |  |                 video_enc.codec_id = video_id; | 
					
						
							|  |  |  |                 type = AV_OPT_FLAG_VIDEO_PARAM; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 avctx = &audio_enc; | 
					
						
							|  |  |  |                 audio_enc.codec_id = audio_id; | 
					
						
							|  |  |  |                 type = AV_OPT_FLAG_AUDIO_PARAM; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |             if (avserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) { | 
					
						
							| 
									
										
										
										
											2010-06-08 09:55:30 +00:00
										 |  |  |                 ERROR("AVPreset error: %s\n", arg); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2007-02-22 13:23:38 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "VideoTag")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if ((strlen(arg) == 4) && stream) | 
					
						
							| 
									
										
										
										
											2010-03-07 22:18:30 +00:00
										 |  |  |                 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]); | 
					
						
							| 
									
										
										
										
											2006-03-09 00:36:39 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "BitExact")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2006-03-09 00:36:39 +00:00
										 |  |  |                 video_enc.flags |= CODEC_FLAG_BITEXACT; | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "DctFastint")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2006-03-09 00:36:39 +00:00
										 |  |  |                 video_enc.dct_algo  = FF_DCT_FASTINT; | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "IdctSimple")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2006-03-09 00:36:39 +00:00
										 |  |  |                 video_enc.idct_algo = FF_IDCT_SIMPLE; | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "Qscale")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 video_enc.flags |= CODEC_FLAG_QSCALE; | 
					
						
							|  |  |  |                 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "VideoQDiff")) { | 
					
						
							| 
									
										
										
										
											2002-09-12 02:31:11 +00:00
										 |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |             if (stream) { | 
					
						
							|  |  |  |                 video_enc.max_qdiff = atoi(arg); | 
					
						
							|  |  |  |                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("VideoQDiff out of range\n"); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "VideoQMax")) { | 
					
						
							| 
									
										
										
										
											2002-09-12 02:31:11 +00:00
										 |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |             if (stream) { | 
					
						
							|  |  |  |                 video_enc.qmax = atoi(arg); | 
					
						
							|  |  |  |                 if (video_enc.qmax < 1 || video_enc.qmax > 31) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("VideoQMax out of range\n"); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "VideoQMin")) { | 
					
						
							| 
									
										
										
										
											2002-09-12 02:31:11 +00:00
										 |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |             if (stream) { | 
					
						
							|  |  |  |                 video_enc.qmin = atoi(arg); | 
					
						
							|  |  |  |                 if (video_enc.qmin < 1 || video_enc.qmin > 31) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("VideoQMin out of range\n"); | 
					
						
							| 
									
										
										
										
											2002-05-16 02:03:07 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-10-21 16:08:39 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "LumaElim")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-10-21 16:08:39 +00:00
										 |  |  |                 video_enc.luma_elim_threshold = atoi(arg); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "ChromaElim")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-10-21 16:08:39 +00:00
										 |  |  |                 video_enc.chroma_elim_threshold = atoi(arg); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "LumiMask")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-10-21 16:08:39 +00:00
										 |  |  |                 video_enc.lumi_masking = atof(arg); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "DarkMask")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-10-21 16:08:39 +00:00
										 |  |  |                 video_enc.dark_masking = atof(arg); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "NoVideo")) { | 
					
						
							|  |  |  |             video_id = CODEC_ID_NONE; | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "NoAudio")) { | 
					
						
							|  |  |  |             audio_id = CODEC_ID_NONE; | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "ACL")) { | 
					
						
							| 
									
										
										
										
											2010-04-07 20:06:02 +00:00
										 |  |  |             parse_acl_row(stream, feed, NULL, p, filename, line_num); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "DynamicACL")) { | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p); | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "RTSPOption")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							|  |  |  |                 av_freep(&stream->rtsp_option); | 
					
						
							| 
									
										
										
										
											2007-03-31 14:36:24 +00:00
										 |  |  |                 stream->rtsp_option = av_strdup(arg); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "MulticastAddress")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							|  |  |  |             if (stream) { | 
					
						
							| 
									
										
										
										
											2007-04-25 21:05:47 +00:00
										 |  |  |                 if (resolve_host(&stream->multicast_ip, arg) != 0) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("Invalid host/IP address: %s\n", arg); | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 stream->is_multicast = 1; | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                 stream->loop = 1; /* default is looping */ | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "MulticastPort")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-11-20 15:00:05 +00:00
										 |  |  |                 stream->multicast_port = atoi(arg); | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "MulticastTTL")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                 stream->multicast_ttl = atoi(arg); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "NoLoop")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (stream) | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |                 stream->loop = 0; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "</Stream>")) { | 
					
						
							|  |  |  |             if (!stream) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("No corresponding <Stream> for </Stream>\n"); | 
					
						
							| 
									
										
										
										
											2008-05-29 02:28:33 +00:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2008-05-29 02:29:33 +00:00
										 |  |  |                 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) { | 
					
						
							|  |  |  |                     if (audio_id != CODEC_ID_NONE) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                         audio_enc.codec_type = AVMEDIA_TYPE_AUDIO; | 
					
						
							| 
									
										
										
										
											2008-05-29 02:29:33 +00:00
										 |  |  |                         audio_enc.codec_id = audio_id; | 
					
						
							|  |  |  |                         add_codec(stream, &audio_enc); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     if (video_id != CODEC_ID_NONE) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                         video_enc.codec_type = AVMEDIA_TYPE_VIDEO; | 
					
						
							| 
									
										
										
										
											2008-05-29 02:29:33 +00:00
										 |  |  |                         video_enc.codec_id = video_id; | 
					
						
							|  |  |  |                         add_codec(stream, &video_enc); | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2008-05-29 02:29:33 +00:00
										 |  |  |                 stream = NULL; | 
					
						
							| 
									
										
										
										
											2008-05-29 02:28:33 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "<Redirect")) { | 
					
						
							|  |  |  |             /*********************************************/ | 
					
						
							|  |  |  |             char *q; | 
					
						
							|  |  |  |             if (stream || feed || redirect) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("Already in a tag\n"); | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 redirect = av_mallocz(sizeof(FFStream)); | 
					
						
							|  |  |  |                 *last_stream = redirect; | 
					
						
							|  |  |  |                 last_stream = &redirect->next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 get_arg(redirect->filename, sizeof(redirect->filename), &p); | 
					
						
							|  |  |  |                 q = strrchr(redirect->filename, '>'); | 
					
						
							|  |  |  |                 if (*q) | 
					
						
							|  |  |  |                     *q = '\0'; | 
					
						
							|  |  |  |                 redirect->stream_type = STREAM_TYPE_REDIRECT; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "URL")) { | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |             if (redirect) | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p); | 
					
						
							|  |  |  |         } else if (!strcasecmp(cmd, "</Redirect>")) { | 
					
						
							|  |  |  |             if (!redirect) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                 ERROR("No corresponding <Redirect> for </Redirect>\n"); | 
					
						
							| 
									
										
										
										
											2008-05-29 02:31:35 +00:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2008-05-29 02:32:02 +00:00
										 |  |  |                 if (!redirect->feed_filename[0]) { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |                     ERROR("No URL found for <Redirect>\n"); | 
					
						
							| 
									
										
										
										
											2008-05-29 02:32:02 +00:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 redirect = NULL; | 
					
						
							| 
									
										
										
										
											2008-05-29 02:31:35 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         } else if (!strcasecmp(cmd, "LoadModule")) { | 
					
						
							|  |  |  |             get_arg(arg, sizeof(arg), &p); | 
					
						
							| 
									
										
										
										
											2009-01-13 23:44:16 +00:00
										 |  |  | #if HAVE_DLOPEN
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             load_module(arg); | 
					
						
							| 
									
										
										
										
											2002-11-30 17:18:59 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |             ERROR("Module support not compiled into this version: '%s'\n", arg); | 
					
						
							| 
									
										
										
										
											2002-11-30 17:18:59 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  |             ERROR("Incorrect keyword: '%s'\n", cmd); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-04-24 10:39:28 +00:00
										 |  |  | #undef ERROR
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     fclose(f); | 
					
						
							|  |  |  |     if (errors) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  | static void handle_child_exit(int sig) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     pid_t pid; | 
					
						
							|  |  |  |     int status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | 
					
						
							|  |  |  |         FFStream *feed; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (feed = first_feed; feed; feed = feed->next) { | 
					
						
							|  |  |  |             if (feed->pid == pid) { | 
					
						
							|  |  |  |                 int uptime = time(0) - feed->pid_start; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 feed->pid = 0; | 
					
						
							|  |  |  |                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-08 19:40:37 +00:00
										 |  |  |                 if (uptime < 30) | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |                     /* Turn off any more restarts */ | 
					
						
							|  |  |  |                     feed->child_argv = 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     need_to_start_children = 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-30 18:44:38 +00:00
										 |  |  | static void opt_debug(void) | 
					
						
							| 
									
										
										
										
											2008-05-21 17:55:54 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     avserver_debug = 1; | 
					
						
							|  |  |  |     avserver_daemon = 0; | 
					
						
							| 
									
										
										
										
											2008-06-21 03:34:18 +00:00
										 |  |  |     logfilename[0] = '-'; | 
					
						
							| 
									
										
										
										
											2008-05-21 17:55:54 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-29 23:12:19 +00:00
										 |  |  | static void show_help(void) | 
					
						
							| 
									
										
										
										
											2008-05-21 17:55:54 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     printf("usage: avserver [options]\n" | 
					
						
							| 
									
										
										
										
											2008-05-21 17:55:54 +00:00
										 |  |  |            "Hyper fast multi format Audio/Video streaming server\n"); | 
					
						
							|  |  |  |     printf("\n"); | 
					
						
							|  |  |  |     show_help_options(options, "Main options:\n", 0, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const OptionDef options[] = { | 
					
						
							| 
									
										
										
										
											2009-11-29 23:12:19 +00:00
										 |  |  | #include "cmdutils_common_opts.h"
 | 
					
						
							| 
									
										
										
										
											2008-05-21 17:55:54 +00:00
										 |  |  |     { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" }, | 
					
						
							|  |  |  |     { "d", 0, {(void*)opt_debug}, "enable debug mode" }, | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/avserver.conf", "configfile" }, | 
					
						
							| 
									
										
										
										
											2008-05-21 17:55:54 +00:00
										 |  |  |     { NULL }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | int main(int argc, char **argv) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |     struct sigaction sigact; | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:07:39 +00:00
										 |  |  |     av_register_all(); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-29 08:48:51 +00:00
										 |  |  |     show_banner(); | 
					
						
							| 
									
										
										
										
											2007-09-28 15:09:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  |     my_program_name = argv[0]; | 
					
						
							| 
									
										
										
										
											2002-10-30 02:15:07 +00:00
										 |  |  |     my_program_dir = getcwd(0, 0); | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     avserver_daemon = 1; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-21 17:55:54 +00:00
										 |  |  |     parse_options(argc, argv, options, NULL); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-07 23:56:00 +00:00
										 |  |  |     unsetenv("http_proxy");             /* Kill the http_proxy */ | 
					
						
							| 
									
										
										
										
											2002-05-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-23 08:53:40 +00:00
										 |  |  |     av_lfg_init(&random_state, av_get_random_seed()); | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-10 02:44:36 +00:00
										 |  |  |     memset(&sigact, 0, sizeof(sigact)); | 
					
						
							|  |  |  |     sigact.sa_handler = handle_child_exit; | 
					
						
							|  |  |  |     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART; | 
					
						
							|  |  |  |     sigaction(SIGCHLD, &sigact, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     if (parse_ffconfig(config_filename) < 0) { | 
					
						
							|  |  |  |         fprintf(stderr, "Incorrect config file - exiting.\n"); | 
					
						
							|  |  |  |         exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-25 18:51:54 +00:00
										 |  |  |     /* open log file if needed */ | 
					
						
							|  |  |  |     if (logfilename[0] != '\0') { | 
					
						
							|  |  |  |         if (!strcmp(logfilename, "-")) | 
					
						
							| 
									
										
										
										
											2008-06-25 19:55:00 +00:00
										 |  |  |             logfile = stdout; | 
					
						
							| 
									
										
										
										
											2008-06-25 18:51:54 +00:00
										 |  |  |         else | 
					
						
							|  |  |  |             logfile = fopen(logfilename, "a"); | 
					
						
							|  |  |  |         av_log_set_callback(http_av_log); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     build_file_streams(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     build_feed_streams(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 18:05:45 +00:00
										 |  |  |     compute_bandwidth(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     /* put the process in background and detach it from its TTY */ | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     if (avserver_daemon) { | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |         int pid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pid = fork(); | 
					
						
							|  |  |  |         if (pid < 0) { | 
					
						
							|  |  |  |             perror("fork"); | 
					
						
							|  |  |  |             exit(1); | 
					
						
							|  |  |  |         } else if (pid > 0) { | 
					
						
							|  |  |  |             /* parent : exit */ | 
					
						
							|  |  |  |             exit(0); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             /* child */ | 
					
						
							|  |  |  |             setsid(); | 
					
						
							|  |  |  |             close(0); | 
					
						
							|  |  |  |             open("/dev/null", O_RDWR); | 
					
						
							| 
									
										
										
										
											2002-07-27 15:22:17 +00:00
										 |  |  |             if (strcmp(logfilename, "-") != 0) { | 
					
						
							| 
									
										
										
										
											2002-07-27 03:03:04 +00:00
										 |  |  |                 close(1); | 
					
						
							|  |  |  |                 dup(0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             close(2); | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |             dup(0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |     /* signal init */ | 
					
						
							|  |  |  |     signal(SIGPIPE, SIG_IGN); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 21:56:56 +02:00
										 |  |  |     if (avserver_daemon) | 
					
						
							| 
									
										
										
										
											2008-06-23 19:43:38 +00:00
										 |  |  |         chdir("/"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-25 16:48:44 +00:00
										 |  |  |     if (http_server() < 0) { | 
					
						
							| 
									
										
										
										
											2008-06-21 03:35:48 +00:00
										 |  |  |         http_log("Could not start server\n"); | 
					
						
							| 
									
										
										
										
											2001-07-22 14:37:44 +00:00
										 |  |  |         exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } |