2 * Multiple format streaming server
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #define _XOPEN_SOURCE 600
26 #define closesocket close
31 /* avformat.h defines LIBAVFORMAT_BUILD, include it before all the other libav* headers which use it */
32 #include "libavformat/avformat.h"
33 #include "libavformat/network.h"
34 #include "libavformat/os_support.h"
35 #include "libavformat/rtpdec.h"
36 #include "libavformat/rtsp.h"
37 #include "libavutil/avstring.h"
38 #include "libavutil/lfg.h"
39 #include "libavutil/random_seed.h"
40 #include "libavutil/intreadwrite.h"
41 #include "libavcodec/opt.h"
45 #include <sys/ioctl.h>
51 #undef time //needed because HAVE_AV_CONFIG_H is defined on top
63 const char program_name
[] = "FFserver";
64 const int program_birth_year
= 2000;
66 static const OptionDef options
[];
69 HTTPSTATE_WAIT_REQUEST
,
70 HTTPSTATE_SEND_HEADER
,
71 HTTPSTATE_SEND_DATA_HEADER
,
72 HTTPSTATE_SEND_DATA
, /* sending TCP or UDP data */
73 HTTPSTATE_SEND_DATA_TRAILER
,
74 HTTPSTATE_RECEIVE_DATA
,
75 HTTPSTATE_WAIT_FEED
, /* wait for data from the feed */
78 RTSPSTATE_WAIT_REQUEST
,
80 RTSPSTATE_SEND_PACKET
,
83 static const char *http_state
[] = {
99 #define IOBUFFER_INIT_SIZE 8192
101 /* timeouts are in ms */
102 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
103 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
105 #define SYNC_TIMEOUT (10 * 1000)
107 typedef struct RTSPActionServerSetup
{
109 char transport_option
[512];
110 } RTSPActionServerSetup
;
113 int64_t count1
, count2
;
114 int64_t time1
, time2
;
117 /* context associated with one connection */
118 typedef struct HTTPContext
{
119 enum HTTPState state
;
120 int fd
; /* socket file descriptor */
121 struct sockaddr_in from_addr
; /* origin */
122 struct pollfd
*poll_entry
; /* used when polling */
124 uint8_t *buffer_ptr
, *buffer_end
;
127 int chunked_encoding
;
128 int chunk_size
; /* 0 if it needs to be read */
129 struct HTTPContext
*next
;
130 int got_key_frame
; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
134 /* input format handling */
135 AVFormatContext
*fmt_in
;
136 int64_t start_time
; /* In milliseconds - this wraps fairly often */
137 int64_t first_pts
; /* initial pts value */
138 int64_t cur_pts
; /* current pts value from the stream in us */
139 int64_t cur_frame_duration
; /* duration of the current frame in us */
140 int cur_frame_bytes
; /* output frame size, needed to compute
141 the time at which we send each
143 int pts_stream_index
; /* stream we choose as clock reference */
144 int64_t cur_clock
; /* current clock reference value in us */
145 /* output format handling */
146 struct FFStream
*stream
;
147 /* -1 is invalid stream */
148 int feed_streams
[MAX_STREAMS
]; /* index of streams in the feed */
149 int switch_feed_streams
[MAX_STREAMS
]; /* index of streams in the feed */
151 AVFormatContext fmt_ctx
; /* instance of FFStream for one user */
152 int last_packet_sent
; /* true if last data packet was sent */
154 DataRateData datarate
;
161 int is_packetized
; /* if true, the stream is packetized */
162 int packet_stream_index
; /* current stream for output in state machine */
164 /* RTSP state specific */
165 uint8_t *pb_buffer
; /* XXX: use that in all the code */
167 int seq
; /* RTSP sequence number */
169 /* RTP state specific */
170 enum RTSPLowerTransport rtp_protocol
;
171 char session_id
[32]; /* session id */
172 AVFormatContext
*rtp_ctx
[MAX_STREAMS
];
174 /* RTP/UDP specific */
175 URLContext
*rtp_handles
[MAX_STREAMS
];
177 /* RTP/TCP specific */
178 struct HTTPContext
*rtsp_c
;
179 uint8_t *packet_buffer
, *packet_buffer_ptr
, *packet_buffer_end
;
182 /* each generated stream is described here */
186 STREAM_TYPE_REDIRECT
,
189 enum IPAddressAction
{
194 typedef struct IPAddressACL
{
195 struct IPAddressACL
*next
;
196 enum IPAddressAction action
;
197 /* These are in host order */
198 struct in_addr first
;
202 /* description of each stream of the ffserver.conf file */
203 typedef struct FFStream
{
204 enum StreamType stream_type
;
205 char filename
[1024]; /* stream filename */
206 struct FFStream
*feed
; /* feed we are using (can be null if
208 AVFormatParameters
*ap_in
; /* input parameters */
209 AVInputFormat
*ifmt
; /* if non NULL, force input format */
213 int prebuffer
; /* Number of millseconds early to start */
214 int64_t max_time
; /* Number of milliseconds to run */
216 AVStream
*streams
[MAX_STREAMS
];
217 int feed_streams
[MAX_STREAMS
]; /* index of streams in the feed */
218 char feed_filename
[1024]; /* file name of the feed storage, or
219 input file name for a stream */
224 pid_t pid
; /* Of ffmpeg process */
225 time_t pid_start
; /* Of ffmpeg process */
227 struct FFStream
*next
;
228 unsigned bandwidth
; /* bandwidth, in kbits/s */
231 /* multicast specific */
233 struct in_addr multicast_ip
;
234 int multicast_port
; /* first port used for multicast */
236 int loop
; /* if true, send the stream in loops (only meaningful if file) */
239 int feed_opened
; /* true if someone is writing to the feed */
240 int is_feed
; /* true if it is a feed */
241 int readonly
; /* True if writing is prohibited to the file */
242 int truncate
; /* True if feeder connection truncate the feed file */
244 int64_t bytes_served
;
245 int64_t feed_max_size
; /* maximum storage size, zero means unlimited */
246 int64_t feed_write_index
; /* current write position in feed (it wraps around) */
247 int64_t feed_size
; /* current size of feed */
248 struct FFStream
*next_feed
;
251 typedef struct FeedData
{
252 long long data_count
;
253 float avg_frame_size
; /* frame size averaged over last frames with exponential mean */
256 static struct sockaddr_in my_http_addr
;
257 static struct sockaddr_in my_rtsp_addr
;
259 static char logfilename
[1024];
260 static HTTPContext
*first_http_ctx
;
261 static FFStream
*first_feed
; /* contains only feeds */
262 static FFStream
*first_stream
; /* contains all streams, including feeds */
264 static void new_connection(int server_fd
, int is_rtsp
);
265 static void close_connection(HTTPContext
*c
);
268 static int handle_connection(HTTPContext
*c
);
269 static int http_parse_request(HTTPContext
*c
);
270 static int http_send_data(HTTPContext
*c
);
271 static void compute_status(HTTPContext
*c
);
272 static int open_input_stream(HTTPContext
*c
, const char *info
);
273 static int http_start_receive_data(HTTPContext
*c
);
274 static int http_receive_data(HTTPContext
*c
);
277 static int rtsp_parse_request(HTTPContext
*c
);
278 static void rtsp_cmd_describe(HTTPContext
*c
, const char *url
);
279 static void rtsp_cmd_options(HTTPContext
*c
, const char *url
);
280 static void rtsp_cmd_setup(HTTPContext
*c
, const char *url
, RTSPMessageHeader
*h
);
281 static void rtsp_cmd_play(HTTPContext
*c
, const char *url
, RTSPMessageHeader
*h
);
282 static void rtsp_cmd_pause(HTTPContext
*c
, const char *url
, RTSPMessageHeader
*h
);
283 static void rtsp_cmd_teardown(HTTPContext
*c
, const char *url
, RTSPMessageHeader
*h
);
286 static int prepare_sdp_description(FFStream
*stream
, uint8_t **pbuffer
,
287 struct in_addr my_ip
);
290 static HTTPContext
*rtp_new_connection(struct sockaddr_in
*from_addr
,
291 FFStream
*stream
, const char *session_id
,
292 enum RTSPLowerTransport rtp_protocol
);
293 static int rtp_new_av_stream(HTTPContext
*c
,
294 int stream_index
, struct sockaddr_in
*dest_addr
,
295 HTTPContext
*rtsp_c
);
297 static const char *my_program_name
;
298 static const char *my_program_dir
;
300 static const char *config_filename
;
301 static int ffserver_debug
;
302 static int ffserver_daemon
;
303 static int no_launch
;
304 static int need_to_start_children
;
306 /* maximum number of simultaneous HTTP connections */
307 static unsigned int nb_max_http_connections
= 2000;
308 static unsigned int nb_max_connections
= 5;
309 static unsigned int nb_connections
;
311 static uint64_t max_bandwidth
= 1000;
312 static uint64_t current_bandwidth
;
314 static int64_t cur_time
; // Making this global saves on passing it around everywhere
316 static AVLFG random_state
;
318 static FILE *logfile
= NULL
;
320 static char *ctime1(char *buf2
)
328 p
= buf2
+ strlen(p
) - 1;
334 static void http_vlog(const char *fmt
, va_list vargs
)
336 static int print_prefix
= 1;
341 fprintf(logfile
, "%s ", buf
);
343 print_prefix
= strstr(fmt
, "\n") != NULL
;
344 vfprintf(logfile
, fmt
, vargs
);
349 static void __attribute__ ((format (printf
, 1, 2))) http_log(const char *fmt
, ...)
352 va_start(vargs
, fmt
);
353 http_vlog(fmt
, vargs
);
357 static void http_av_log(void *ptr
, int level
, const char *fmt
, va_list vargs
)
359 static int print_prefix
= 1;
360 AVClass
*avc
= ptr ?
*(AVClass
**)ptr
: NULL
;
361 if (level
> av_log_get_level())
363 if (print_prefix
&& avc
)
364 http_log("[%s @ %p]", avc
->item_name(ptr
), ptr
);
365 print_prefix
= strstr(fmt
, "\n") != NULL
;
366 http_vlog(fmt
, vargs
);
369 static void log_connection(HTTPContext
*c
)
374 http_log("%s - - [%s] \"%s %s\" %d %"PRId64
"\n",
375 inet_ntoa(c
->from_addr
.sin_addr
), c
->method
, c
->url
,
376 c
->protocol
, (c
->http_error ? c
->http_error
: 200), c
->data_count
);
379 static void update_datarate(DataRateData
*drd
, int64_t count
)
381 if (!drd
->time1
&& !drd
->count1
) {
382 drd
->time1
= drd
->time2
= cur_time
;
383 drd
->count1
= drd
->count2
= count
;
384 } else if (cur_time
- drd
->time2
> 5000) {
385 drd
->time1
= drd
->time2
;
386 drd
->count1
= drd
->count2
;
387 drd
->time2
= cur_time
;
392 /* In bytes per second */
393 static int compute_datarate(DataRateData
*drd
, int64_t count
)
395 if (cur_time
== drd
->time1
)
398 return ((count
- drd
->count1
) * 1000) / (cur_time
- drd
->time1
);
402 static void start_children(FFStream
*feed
)
407 for (; feed
; feed
= feed
->next
) {
408 if (feed
->child_argv
&& !feed
->pid
) {
409 feed
->pid_start
= time(0);
414 http_log("Unable to create children\n");
423 av_strlcpy(pathname
, my_program_name
, sizeof(pathname
));
425 slash
= strrchr(pathname
, '/');
430 strcpy(slash
, "ffmpeg");
432 http_log("Launch commandline: ");
433 http_log("%s ", pathname
);
434 for (i
= 1; feed
->child_argv
[i
] && feed
->child_argv
[i
][0]; i
++)
435 http_log("%s ", feed
->child_argv
[i
]);
438 for (i
= 3; i
< 256; i
++)
441 if (!ffserver_debug
) {
442 i
= open("/dev/null", O_RDWR
);
451 /* This is needed to make relative pathnames work */
452 chdir(my_program_dir
);
454 signal(SIGPIPE
, SIG_DFL
);
456 execvp(pathname
, feed
->child_argv
);
464 /* open a listening socket */
465 static int socket_open_listen(struct sockaddr_in
*my_addr
)
469 server_fd
= socket(AF_INET
,SOCK_STREAM
,0);
476 setsockopt(server_fd
, SOL_SOCKET
, SO_REUSEADDR
, &tmp
, sizeof(tmp
));
478 if (bind (server_fd
, (struct sockaddr
*) my_addr
, sizeof (*my_addr
)) < 0) {
480 snprintf(bindmsg
, sizeof(bindmsg
), "bind(port %d)", ntohs(my_addr
->sin_port
));
482 closesocket(server_fd
);
486 if (listen (server_fd
, 5) < 0) {
488 closesocket(server_fd
);
491 ff_socket_nonblock(server_fd
, 1);
496 /* start all multicast streams */
497 static void start_multicast(void)
502 struct sockaddr_in dest_addr
;
503 int default_port
, stream_index
;
506 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
507 if (stream
->is_multicast
) {
508 /* open the RTP connection */
509 snprintf(session_id
, sizeof(session_id
), "%08x%08x",
510 av_lfg_get(&random_state
), av_lfg_get(&random_state
));
512 /* choose a port if none given */
513 if (stream
->multicast_port
== 0) {
514 stream
->multicast_port
= default_port
;
518 dest_addr
.sin_family
= AF_INET
;
519 dest_addr
.sin_addr
= stream
->multicast_ip
;
520 dest_addr
.sin_port
= htons(stream
->multicast_port
);
522 rtp_c
= rtp_new_connection(&dest_addr
, stream
, session_id
,
523 RTSP_LOWER_TRANSPORT_UDP_MULTICAST
);
527 if (open_input_stream(rtp_c
, "") < 0) {
528 http_log("Could not open input stream for stream '%s'\n",
533 /* open each RTP stream */
534 for(stream_index
= 0; stream_index
< stream
->nb_streams
;
536 dest_addr
.sin_port
= htons(stream
->multicast_port
+
538 if (rtp_new_av_stream(rtp_c
, stream_index
, &dest_addr
, NULL
) < 0) {
539 http_log("Could not open output stream '%s/streamid=%d'\n",
540 stream
->filename
, stream_index
);
545 /* change state to send data */
546 rtp_c
->state
= HTTPSTATE_SEND_DATA
;
551 /* main loop of the http server */
552 static int http_server(void)
554 int server_fd
= 0, rtsp_server_fd
= 0;
555 int ret
, delay
, delay1
;
556 struct pollfd
*poll_table
, *poll_entry
;
557 HTTPContext
*c
, *c_next
;
559 if(!(poll_table
= av_mallocz((nb_max_http_connections
+ 2)*sizeof(*poll_table
)))) {
560 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections
);
564 if (my_http_addr
.sin_port
) {
565 server_fd
= socket_open_listen(&my_http_addr
);
570 if (my_rtsp_addr
.sin_port
) {
571 rtsp_server_fd
= socket_open_listen(&my_rtsp_addr
);
572 if (rtsp_server_fd
< 0)
576 if (!rtsp_server_fd
&& !server_fd
) {
577 http_log("HTTP and RTSP disabled.\n");
581 http_log("FFserver started.\n");
583 start_children(first_feed
);
588 poll_entry
= poll_table
;
590 poll_entry
->fd
= server_fd
;
591 poll_entry
->events
= POLLIN
;
594 if (rtsp_server_fd
) {
595 poll_entry
->fd
= rtsp_server_fd
;
596 poll_entry
->events
= POLLIN
;
600 /* wait for events on each HTTP handle */
607 case HTTPSTATE_SEND_HEADER
:
608 case RTSPSTATE_SEND_REPLY
:
609 case RTSPSTATE_SEND_PACKET
:
610 c
->poll_entry
= poll_entry
;
612 poll_entry
->events
= POLLOUT
;
615 case HTTPSTATE_SEND_DATA_HEADER
:
616 case HTTPSTATE_SEND_DATA
:
617 case HTTPSTATE_SEND_DATA_TRAILER
:
618 if (!c
->is_packetized
) {
619 /* for TCP, we output as much as we can (may need to put a limit) */
620 c
->poll_entry
= poll_entry
;
622 poll_entry
->events
= POLLOUT
;
625 /* when ffserver is doing the timing, we work by
626 looking at which packet need to be sent every
628 delay1
= 10; /* one tick wait XXX: 10 ms assumed */
633 case HTTPSTATE_WAIT_REQUEST
:
634 case HTTPSTATE_RECEIVE_DATA
:
635 case HTTPSTATE_WAIT_FEED
:
636 case RTSPSTATE_WAIT_REQUEST
:
637 /* need to catch errors */
638 c
->poll_entry
= poll_entry
;
640 poll_entry
->events
= POLLIN
;/* Maybe this will work */
644 c
->poll_entry
= NULL
;
650 /* wait for an event on one connection. We poll at least every
651 second to handle timeouts */
653 ret
= poll(poll_table
, poll_entry
- poll_table
, delay
);
654 if (ret
< 0 && ff_neterrno() != FF_NETERROR(EAGAIN
) &&
655 ff_neterrno() != FF_NETERROR(EINTR
))
659 cur_time
= av_gettime() / 1000;
661 if (need_to_start_children
) {
662 need_to_start_children
= 0;
663 start_children(first_feed
);
666 /* now handle the events */
667 for(c
= first_http_ctx
; c
!= NULL
; c
= c_next
) {
669 if (handle_connection(c
) < 0) {
670 /* close and free the connection */
676 poll_entry
= poll_table
;
678 /* new HTTP connection request ? */
679 if (poll_entry
->revents
& POLLIN
)
680 new_connection(server_fd
, 0);
683 if (rtsp_server_fd
) {
684 /* new RTSP connection request ? */
685 if (poll_entry
->revents
& POLLIN
)
686 new_connection(rtsp_server_fd
, 1);
691 /* start waiting for a new HTTP/RTSP request */
692 static void start_wait_request(HTTPContext
*c
, int is_rtsp
)
694 c
->buffer_ptr
= c
->buffer
;
695 c
->buffer_end
= c
->buffer
+ c
->buffer_size
- 1; /* leave room for '\0' */
698 c
->timeout
= cur_time
+ RTSP_REQUEST_TIMEOUT
;
699 c
->state
= RTSPSTATE_WAIT_REQUEST
;
701 c
->timeout
= cur_time
+ HTTP_REQUEST_TIMEOUT
;
702 c
->state
= HTTPSTATE_WAIT_REQUEST
;
706 static void http_send_too_busy_reply(int fd
)
709 int len
= snprintf(buffer
, sizeof(buffer
),
710 "HTTP/1.0 200 Server too busy\r\n"
711 "Content-type: text/html\r\n"
713 "<html><head><title>Too busy</title></head><body>\r\n"
714 "<p>The server is too busy to serve your request at this time.</p>\r\n"
715 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
716 "</body></html>\r\n",
717 nb_connections
, nb_max_connections
);
718 send(fd
, buffer
, len
, 0);
722 static void new_connection(int server_fd
, int is_rtsp
)
724 struct sockaddr_in from_addr
;
726 HTTPContext
*c
= NULL
;
728 len
= sizeof(from_addr
);
729 fd
= accept(server_fd
, (struct sockaddr
*)&from_addr
,
732 http_log("error during accept %s\n", strerror(errno
));
735 ff_socket_nonblock(fd
, 1);
737 if (nb_connections
>= nb_max_connections
) {
738 http_send_too_busy_reply(fd
);
742 /* add a new connection */
743 c
= av_mallocz(sizeof(HTTPContext
));
748 c
->poll_entry
= NULL
;
749 c
->from_addr
= from_addr
;
750 c
->buffer_size
= IOBUFFER_INIT_SIZE
;
751 c
->buffer
= av_malloc(c
->buffer_size
);
755 c
->next
= first_http_ctx
;
759 start_wait_request(c
, is_rtsp
);
771 static void close_connection(HTTPContext
*c
)
773 HTTPContext
**cp
, *c1
;
775 AVFormatContext
*ctx
;
779 /* remove connection from list */
780 cp
= &first_http_ctx
;
781 while ((*cp
) != NULL
) {
789 /* remove references, if any (XXX: do it faster) */
790 for(c1
= first_http_ctx
; c1
!= NULL
; c1
= c1
->next
) {
795 /* remove connection associated resources */
799 /* close each frame parser */
800 for(i
=0;i
<c
->fmt_in
->nb_streams
;i
++) {
801 st
= c
->fmt_in
->streams
[i
];
802 if (st
->codec
->codec
)
803 avcodec_close(st
->codec
);
805 av_close_input_file(c
->fmt_in
);
808 /* free RTP output streams if any */
811 nb_streams
= c
->stream
->nb_streams
;
813 for(i
=0;i
<nb_streams
;i
++) {
816 av_write_trailer(ctx
);
819 h
= c
->rtp_handles
[i
];
826 if (!c
->last_packet_sent
&& c
->state
== HTTPSTATE_SEND_DATA_TRAILER
) {
829 if (url_open_dyn_buf(&ctx
->pb
) >= 0) {
830 av_write_trailer(ctx
);
831 av_freep(&c
->pb_buffer
);
832 url_close_dyn_buf(ctx
->pb
, &c
->pb_buffer
);
837 for(i
=0; i
<ctx
->nb_streams
; i
++)
838 av_free(ctx
->streams
[i
]);
840 if (c
->stream
&& !c
->post
&& c
->stream
->stream_type
== STREAM_TYPE_LIVE
)
841 current_bandwidth
-= c
->stream
->bandwidth
;
843 /* signal that there is no feed if we are the feeder socket */
844 if (c
->state
== HTTPSTATE_RECEIVE_DATA
&& c
->stream
) {
845 c
->stream
->feed_opened
= 0;
849 av_freep(&c
->pb_buffer
);
850 av_freep(&c
->packet_buffer
);
856 static int handle_connection(HTTPContext
*c
)
861 case HTTPSTATE_WAIT_REQUEST
:
862 case RTSPSTATE_WAIT_REQUEST
:
864 if ((c
->timeout
- cur_time
) < 0)
866 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
))
869 /* no need to read if no events */
870 if (!(c
->poll_entry
->revents
& POLLIN
))
874 len
= recv(c
->fd
, c
->buffer_ptr
, 1, 0);
876 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
877 ff_neterrno() != FF_NETERROR(EINTR
))
879 } else if (len
== 0) {
882 /* search for end of request. */
884 c
->buffer_ptr
+= len
;
886 if ((ptr
>= c
->buffer
+ 2 && !memcmp(ptr
-2, "\n\n", 2)) ||
887 (ptr
>= c
->buffer
+ 4 && !memcmp(ptr
-4, "\r\n\r\n", 4))) {
888 /* request found : parse it and reply */
889 if (c
->state
== HTTPSTATE_WAIT_REQUEST
) {
890 ret
= http_parse_request(c
);
892 ret
= rtsp_parse_request(c
);
896 } else if (ptr
>= c
->buffer_end
) {
897 /* request too long: cannot do anything */
899 } else goto read_loop
;
903 case HTTPSTATE_SEND_HEADER
:
904 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
))
907 /* no need to write if no events */
908 if (!(c
->poll_entry
->revents
& POLLOUT
))
910 len
= send(c
->fd
, c
->buffer_ptr
, c
->buffer_end
- c
->buffer_ptr
, 0);
912 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
913 ff_neterrno() != FF_NETERROR(EINTR
)) {
914 /* error : close connection */
915 av_freep(&c
->pb_buffer
);
919 c
->buffer_ptr
+= len
;
921 c
->stream
->bytes_served
+= len
;
922 c
->data_count
+= len
;
923 if (c
->buffer_ptr
>= c
->buffer_end
) {
924 av_freep(&c
->pb_buffer
);
928 /* all the buffer was sent : synchronize to the incoming stream */
929 c
->state
= HTTPSTATE_SEND_DATA_HEADER
;
930 c
->buffer_ptr
= c
->buffer_end
= c
->buffer
;
935 case HTTPSTATE_SEND_DATA
:
936 case HTTPSTATE_SEND_DATA_HEADER
:
937 case HTTPSTATE_SEND_DATA_TRAILER
:
938 /* for packetized output, we consider we can always write (the
939 input streams sets the speed). It may be better to verify
940 that we do not rely too much on the kernel queues */
941 if (!c
->is_packetized
) {
942 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
))
945 /* no need to read if no events */
946 if (!(c
->poll_entry
->revents
& POLLOUT
))
949 if (http_send_data(c
) < 0)
951 /* close connection if trailer sent */
952 if (c
->state
== HTTPSTATE_SEND_DATA_TRAILER
)
955 case HTTPSTATE_RECEIVE_DATA
:
956 /* no need to read if no events */
957 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
))
959 if (!(c
->poll_entry
->revents
& POLLIN
))
961 if (http_receive_data(c
) < 0)
964 case HTTPSTATE_WAIT_FEED
:
965 /* no need to read if no events */
966 if (c
->poll_entry
->revents
& (POLLIN
| POLLERR
| POLLHUP
))
969 /* nothing to do, we'll be waken up by incoming feed packets */
972 case RTSPSTATE_SEND_REPLY
:
973 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
)) {
974 av_freep(&c
->pb_buffer
);
977 /* no need to write if no events */
978 if (!(c
->poll_entry
->revents
& POLLOUT
))
980 len
= send(c
->fd
, c
->buffer_ptr
, c
->buffer_end
- c
->buffer_ptr
, 0);
982 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
983 ff_neterrno() != FF_NETERROR(EINTR
)) {
984 /* error : close connection */
985 av_freep(&c
->pb_buffer
);
989 c
->buffer_ptr
+= len
;
990 c
->data_count
+= len
;
991 if (c
->buffer_ptr
>= c
->buffer_end
) {
992 /* all the buffer was sent : wait for a new request */
993 av_freep(&c
->pb_buffer
);
994 start_wait_request(c
, 1);
998 case RTSPSTATE_SEND_PACKET
:
999 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
)) {
1000 av_freep(&c
->packet_buffer
);
1003 /* no need to write if no events */
1004 if (!(c
->poll_entry
->revents
& POLLOUT
))
1006 len
= send(c
->fd
, c
->packet_buffer_ptr
,
1007 c
->packet_buffer_end
- c
->packet_buffer_ptr
, 0);
1009 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
1010 ff_neterrno() != FF_NETERROR(EINTR
)) {
1011 /* error : close connection */
1012 av_freep(&c
->packet_buffer
);
1016 c
->packet_buffer_ptr
+= len
;
1017 if (c
->packet_buffer_ptr
>= c
->packet_buffer_end
) {
1018 /* all the buffer was sent : wait for a new request */
1019 av_freep(&c
->packet_buffer
);
1020 c
->state
= RTSPSTATE_WAIT_REQUEST
;
1024 case HTTPSTATE_READY
:
1033 static int extract_rates(char *rates
, int ratelen
, const char *request
)
1037 for (p
= request
; *p
&& *p
!= '\r' && *p
!= '\n'; ) {
1038 if (strncasecmp(p
, "Pragma:", 7) == 0) {
1039 const char *q
= p
+ 7;
1041 while (*q
&& *q
!= '\n' && isspace(*q
))
1044 if (strncasecmp(q
, "stream-switch-entry=", 20) == 0) {
1050 memset(rates
, 0xff, ratelen
);
1053 while (*q
&& *q
!= '\n' && *q
!= ':')
1056 if (sscanf(q
, ":%d:%d", &stream_no
, &rate_no
) != 2)
1060 if (stream_no
< ratelen
&& stream_no
>= 0)
1061 rates
[stream_no
] = rate_no
;
1063 while (*q
&& *q
!= '\n' && !isspace(*q
))
1070 p
= strchr(p
, '\n');
1080 static int find_stream_in_feed(FFStream
*feed
, AVCodecContext
*codec
, int bit_rate
)
1083 int best_bitrate
= 100000000;
1086 for (i
= 0; i
< feed
->nb_streams
; i
++) {
1087 AVCodecContext
*feed_codec
= feed
->streams
[i
]->codec
;
1089 if (feed_codec
->codec_id
!= codec
->codec_id
||
1090 feed_codec
->sample_rate
!= codec
->sample_rate
||
1091 feed_codec
->width
!= codec
->width
||
1092 feed_codec
->height
!= codec
->height
)
1095 /* Potential stream */
1097 /* We want the fastest stream less than bit_rate, or the slowest
1098 * faster than bit_rate
1101 if (feed_codec
->bit_rate
<= bit_rate
) {
1102 if (best_bitrate
> bit_rate
|| feed_codec
->bit_rate
> best_bitrate
) {
1103 best_bitrate
= feed_codec
->bit_rate
;
1107 if (feed_codec
->bit_rate
< best_bitrate
) {
1108 best_bitrate
= feed_codec
->bit_rate
;
1117 static int modify_current_stream(HTTPContext
*c
, char *rates
)
1120 FFStream
*req
= c
->stream
;
1121 int action_required
= 0;
1123 /* Not much we can do for a feed */
1127 for (i
= 0; i
< req
->nb_streams
; i
++) {
1128 AVCodecContext
*codec
= req
->streams
[i
]->codec
;
1132 c
->switch_feed_streams
[i
] = req
->feed_streams
[i
];
1135 c
->switch_feed_streams
[i
] = find_stream_in_feed(req
->feed
, codec
, codec
->bit_rate
/ 2);
1138 /* Wants off or slow */
1139 c
->switch_feed_streams
[i
] = find_stream_in_feed(req
->feed
, codec
, codec
->bit_rate
/ 4);
1141 /* This doesn't work well when it turns off the only stream! */
1142 c
->switch_feed_streams
[i
] = -2;
1143 c
->feed_streams
[i
] = -2;
1148 if (c
->switch_feed_streams
[i
] >= 0 && c
->switch_feed_streams
[i
] != c
->feed_streams
[i
])
1149 action_required
= 1;
1152 return action_required
;
1156 static void do_switch_stream(HTTPContext
*c
, int i
)
1158 if (c
->switch_feed_streams
[i
] >= 0) {
1160 c
->feed_streams
[i
] = c
->switch_feed_streams
[i
];
1163 /* Now update the stream */
1165 c
->switch_feed_streams
[i
] = -1;
1168 /* XXX: factorize in utils.c ? */
1169 /* XXX: take care with different space meaning */
1170 static void skip_spaces(const char **pp
)
1174 while (*p
== ' ' || *p
== '\t')
1179 static void get_word(char *buf
, int buf_size
, const char **pp
)
1187 while (!isspace(*p
) && *p
!= '\0') {
1188 if ((q
- buf
) < buf_size
- 1)
1197 static void get_arg(char *buf
, int buf_size
, const char **pp
)
1204 while (isspace(*p
)) p
++;
1207 if (*p
== '\"' || *p
== '\'')
1219 if ((q
- buf
) < buf_size
- 1)
1224 if (quote
&& *p
== quote
)
1229 static int validate_acl(FFStream
*stream
, HTTPContext
*c
)
1231 enum IPAddressAction last_action
= IP_DENY
;
1233 struct in_addr
*src
= &c
->from_addr
.sin_addr
;
1234 unsigned long src_addr
= src
->s_addr
;
1236 for (acl
= stream
->acl
; acl
; acl
= acl
->next
) {
1237 if (src_addr
>= acl
->first
.s_addr
&& src_addr
<= acl
->last
.s_addr
)
1238 return (acl
->action
== IP_ALLOW
) ?
1 : 0;
1239 last_action
= acl
->action
;
1242 /* Nothing matched, so return not the last action */
1243 return (last_action
== IP_DENY
) ?
1 : 0;
1246 /* compute the real filename of a file by matching it without its
1247 extensions to all the stream filenames */
1248 static void compute_real_filename(char *filename
, int max_size
)
1255 /* compute filename by matching without the file extensions */
1256 av_strlcpy(file1
, filename
, sizeof(file1
));
1257 p
= strrchr(file1
, '.');
1260 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
1261 av_strlcpy(file2
, stream
->filename
, sizeof(file2
));
1262 p
= strrchr(file2
, '.');
1265 if (!strcmp(file1
, file2
)) {
1266 av_strlcpy(filename
, stream
->filename
, max_size
);
1281 /* parse http request and prepare header */
1282 static int http_parse_request(HTTPContext
*c
)
1285 enum RedirType redir_type
;
1287 char info
[1024], filename
[1024];
1291 const char *mime_type
;
1295 char *useragent
= 0;
1298 get_word(cmd
, sizeof(cmd
), (const char **)&p
);
1299 av_strlcpy(c
->method
, cmd
, sizeof(c
->method
));
1301 if (!strcmp(cmd
, "GET"))
1303 else if (!strcmp(cmd
, "POST"))
1308 get_word(url
, sizeof(url
), (const char **)&p
);
1309 av_strlcpy(c
->url
, url
, sizeof(c
->url
));
1311 get_word(protocol
, sizeof(protocol
), (const char **)&p
);
1312 if (strcmp(protocol
, "HTTP/1.0") && strcmp(protocol
, "HTTP/1.1"))
1315 av_strlcpy(c
->protocol
, protocol
, sizeof(c
->protocol
));
1318 http_log("%s - - New connection: %s %s\n", inet_ntoa(c
->from_addr
.sin_addr
), cmd
, url
);
1320 /* find the filename and the optional info string in the request */
1321 p
= strchr(url
, '?');
1323 av_strlcpy(info
, p
, sizeof(info
));
1328 av_strlcpy(filename
, url
+ ((*url
== '/') ?
1 : 0), sizeof(filename
)-1);
1330 for (p
= c
->buffer
; *p
&& *p
!= '\r' && *p
!= '\n'; ) {
1331 if (strncasecmp(p
, "User-Agent:", 11) == 0) {
1333 if (*useragent
&& *useragent
!= '\n' && isspace(*useragent
))
1337 p
= strchr(p
, '\n');
1344 redir_type
= REDIR_NONE
;
1345 if (av_match_ext(filename
, "asx")) {
1346 redir_type
= REDIR_ASX
;
1347 filename
[strlen(filename
)-1] = 'f';
1348 } else if (av_match_ext(filename
, "asf") &&
1349 (!useragent
|| strncasecmp(useragent
, "NSPlayer", 8) != 0)) {
1350 /* if this isn't WMP or lookalike, return the redirector file */
1351 redir_type
= REDIR_ASF
;
1352 } else if (av_match_ext(filename
, "rpm,ram")) {
1353 redir_type
= REDIR_RAM
;
1354 strcpy(filename
+ strlen(filename
)-2, "m");
1355 } else if (av_match_ext(filename
, "rtsp")) {
1356 redir_type
= REDIR_RTSP
;
1357 compute_real_filename(filename
, sizeof(filename
) - 1);
1358 } else if (av_match_ext(filename
, "sdp")) {
1359 redir_type
= REDIR_SDP
;
1360 compute_real_filename(filename
, sizeof(filename
) - 1);
1363 // "redirect" / request to index.html
1364 if (!strlen(filename
))
1365 av_strlcpy(filename
, "index.html", sizeof(filename
) - 1);
1367 stream
= first_stream
;
1368 while (stream
!= NULL
) {
1369 if (!strcmp(stream
->filename
, filename
) && validate_acl(stream
, c
))
1371 stream
= stream
->next
;
1373 if (stream
== NULL
) {
1374 snprintf(msg
, sizeof(msg
), "File '%s' not found", url
);
1375 http_log("File '%s' not found\n", url
);
1380 memcpy(c
->feed_streams
, stream
->feed_streams
, sizeof(c
->feed_streams
));
1381 memset(c
->switch_feed_streams
, -1, sizeof(c
->switch_feed_streams
));
1383 if (stream
->stream_type
== STREAM_TYPE_REDIRECT
) {
1384 c
->http_error
= 301;
1386 q
+= snprintf(q
, c
->buffer_size
,
1387 "HTTP/1.0 301 Moved\r\n"
1389 "Content-type: text/html\r\n"
1391 "<html><head><title>Moved</title></head><body>\r\n"
1392 "You should be <a href=\"%s\">redirected</a>.\r\n"
1393 "</body></html>\r\n", stream
->feed_filename
, stream
->feed_filename
);
1394 /* prepare output buffer */
1395 c
->buffer_ptr
= c
->buffer
;
1397 c
->state
= HTTPSTATE_SEND_HEADER
;
1401 /* If this is WMP, get the rate information */
1402 if (extract_rates(ratebuf
, sizeof(ratebuf
), c
->buffer
)) {
1403 if (modify_current_stream(c
, ratebuf
)) {
1404 for (i
= 0; i
< FF_ARRAY_ELEMS(c
->feed_streams
); i
++) {
1405 if (c
->switch_feed_streams
[i
] >= 0)
1406 do_switch_stream(c
, i
);
1411 if (c
->post
== 0 && stream
->stream_type
== STREAM_TYPE_LIVE
)
1412 current_bandwidth
+= stream
->bandwidth
;
1414 /* If already streaming this feed, do not let start another feeder. */
1415 if (stream
->feed_opened
) {
1416 snprintf(msg
, sizeof(msg
), "This feed is already being received.");
1417 http_log("Feed '%s' already being received\n", stream
->feed_filename
);
1421 if (c
->post
== 0 && max_bandwidth
< current_bandwidth
) {
1422 c
->http_error
= 200;
1424 q
+= snprintf(q
, c
->buffer_size
,
1425 "HTTP/1.0 200 Server too busy\r\n"
1426 "Content-type: text/html\r\n"
1428 "<html><head><title>Too busy</title></head><body>\r\n"
1429 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1430 "<p>The bandwidth being served (including your stream) is %"PRIu64
"kbit/sec, "
1431 "and this exceeds the limit of %"PRIu64
"kbit/sec.</p>\r\n"
1432 "</body></html>\r\n", current_bandwidth
, max_bandwidth
);
1433 /* prepare output buffer */
1434 c
->buffer_ptr
= c
->buffer
;
1436 c
->state
= HTTPSTATE_SEND_HEADER
;
1440 if (redir_type
!= REDIR_NONE
) {
1443 for (p
= c
->buffer
; *p
&& *p
!= '\r' && *p
!= '\n'; ) {
1444 if (strncasecmp(p
, "Host:", 5) == 0) {
1448 p
= strchr(p
, '\n');
1459 while (isspace(*hostinfo
))
1462 eoh
= strchr(hostinfo
, '\n');
1464 if (eoh
[-1] == '\r')
1467 if (eoh
- hostinfo
< sizeof(hostbuf
) - 1) {
1468 memcpy(hostbuf
, hostinfo
, eoh
- hostinfo
);
1469 hostbuf
[eoh
- hostinfo
] = 0;
1471 c
->http_error
= 200;
1473 switch(redir_type
) {
1475 q
+= snprintf(q
, c
->buffer_size
,
1476 "HTTP/1.0 200 ASX Follows\r\n"
1477 "Content-type: video/x-ms-asf\r\n"
1479 "<ASX Version=\"3\">\r\n"
1480 //"<!-- Autogenerated by ffserver -->\r\n"
1481 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1482 "</ASX>\r\n", hostbuf
, filename
, info
);
1485 q
+= snprintf(q
, c
->buffer_size
,
1486 "HTTP/1.0 200 RAM Follows\r\n"
1487 "Content-type: audio/x-pn-realaudio\r\n"
1489 "# Autogenerated by ffserver\r\n"
1490 "http://%s/%s%s\r\n", hostbuf
, filename
, info
);
1493 q
+= snprintf(q
, c
->buffer_size
,
1494 "HTTP/1.0 200 ASF Redirect follows\r\n"
1495 "Content-type: video/x-ms-asf\r\n"
1498 "Ref1=http://%s/%s%s\r\n", hostbuf
, filename
, info
);
1502 char hostname
[256], *p
;
1503 /* extract only hostname */
1504 av_strlcpy(hostname
, hostbuf
, sizeof(hostname
));
1505 p
= strrchr(hostname
, ':');
1508 q
+= snprintf(q
, c
->buffer_size
,
1509 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1510 /* XXX: incorrect mime type ? */
1511 "Content-type: application/x-rtsp\r\n"
1513 "rtsp://%s:%d/%s\r\n", hostname
, ntohs(my_rtsp_addr
.sin_port
), filename
);
1519 int sdp_data_size
, len
;
1520 struct sockaddr_in my_addr
;
1522 q
+= snprintf(q
, c
->buffer_size
,
1523 "HTTP/1.0 200 OK\r\n"
1524 "Content-type: application/sdp\r\n"
1527 len
= sizeof(my_addr
);
1528 getsockname(c
->fd
, (struct sockaddr
*)&my_addr
, &len
);
1530 /* XXX: should use a dynamic buffer */
1531 sdp_data_size
= prepare_sdp_description(stream
,
1534 if (sdp_data_size
> 0) {
1535 memcpy(q
, sdp_data
, sdp_data_size
);
1547 /* prepare output buffer */
1548 c
->buffer_ptr
= c
->buffer
;
1550 c
->state
= HTTPSTATE_SEND_HEADER
;
1556 snprintf(msg
, sizeof(msg
), "ASX/RAM file not handled");
1560 stream
->conns_served
++;
1562 /* XXX: add there authenticate and IP match */
1565 /* if post, it means a feed is being sent */
1566 if (!stream
->is_feed
) {
1567 /* However it might be a status report from WMP! Let us log the
1568 * data as it might come in handy one day. */
1572 for (p
= c
->buffer
; *p
&& *p
!= '\r' && *p
!= '\n'; ) {
1573 if (strncasecmp(p
, "Pragma: log-line=", 17) == 0) {
1577 if (strncasecmp(p
, "Pragma: client-id=", 18) == 0)
1578 client_id
= strtol(p
+ 18, 0, 10);
1579 p
= strchr(p
, '\n');
1587 char *eol
= strchr(logline
, '\n');
1592 if (eol
[-1] == '\r')
1594 http_log("%.*s\n", (int) (eol
- logline
), logline
);
1595 c
->suppress_log
= 1;
1600 http_log("\nGot request:\n%s\n", c
->buffer
);
1603 if (client_id
&& extract_rates(ratebuf
, sizeof(ratebuf
), c
->buffer
)) {
1606 /* Now we have to find the client_id */
1607 for (wmpc
= first_http_ctx
; wmpc
; wmpc
= wmpc
->next
) {
1608 if (wmpc
->wmp_client_id
== client_id
)
1612 if (wmpc
&& modify_current_stream(wmpc
, ratebuf
))
1613 wmpc
->switch_pending
= 1;
1616 snprintf(msg
, sizeof(msg
), "POST command not handled");
1620 if (http_start_receive_data(c
) < 0) {
1621 snprintf(msg
, sizeof(msg
), "could not open feed");
1625 c
->state
= HTTPSTATE_RECEIVE_DATA
;
1630 if (strcmp(stream
->filename
+ strlen(stream
->filename
) - 4, ".asf") == 0)
1631 http_log("\nGot request:\n%s\n", c
->buffer
);
1634 if (c
->stream
->stream_type
== STREAM_TYPE_STATUS
)
1637 /* open input stream */
1638 if (open_input_stream(c
, info
) < 0) {
1639 snprintf(msg
, sizeof(msg
), "Input stream corresponding to '%s' not found", url
);
1643 /* prepare http header */
1645 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 200 OK\r\n");
1646 mime_type
= c
->stream
->fmt
->mime_type
;
1648 mime_type
= "application/x-octet-stream";
1649 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Pragma: no-cache\r\n");
1651 /* for asf, we need extra headers */
1652 if (!strcmp(c
->stream
->fmt
->name
,"asf_stream")) {
1653 /* Need to allocate a client id */
1655 c
->wmp_client_id
= av_lfg_get(&random_state
);
1657 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
);
1659 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-Type: %s\r\n", mime_type
);
1660 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1662 /* prepare output buffer */
1664 c
->buffer_ptr
= c
->buffer
;
1666 c
->state
= HTTPSTATE_SEND_HEADER
;
1669 c
->http_error
= 404;
1671 q
+= snprintf(q
, c
->buffer_size
,
1672 "HTTP/1.0 404 Not Found\r\n"
1673 "Content-type: text/html\r\n"
1676 "<head><title>404 Not Found</title></head>\n"
1679 /* prepare output buffer */
1680 c
->buffer_ptr
= c
->buffer
;
1682 c
->state
= HTTPSTATE_SEND_HEADER
;
1686 c
->http_error
= 200; /* horrible : we use this value to avoid
1687 going to the send data state */
1688 c
->state
= HTTPSTATE_SEND_HEADER
;
1692 static void fmt_bytecount(ByteIOContext
*pb
, int64_t count
)
1694 static const char *suffix
= " kMGTP";
1697 for (s
= suffix
; count
>= 100000 && s
[1]; count
/= 1000, s
++);
1699 url_fprintf(pb
, "%"PRId64
"%c", count
, *s
);
1702 static void compute_status(HTTPContext
*c
)
1711 if (url_open_dyn_buf(&pb
) < 0) {
1712 /* XXX: return an error ? */
1713 c
->buffer_ptr
= c
->buffer
;
1714 c
->buffer_end
= c
->buffer
;
1718 url_fprintf(pb
, "HTTP/1.0 200 OK\r\n");
1719 url_fprintf(pb
, "Content-type: %s\r\n", "text/html");
1720 url_fprintf(pb
, "Pragma: no-cache\r\n");
1721 url_fprintf(pb
, "\r\n");
1723 url_fprintf(pb
, "<html><head><title>%s Status</title>\n", program_name
);
1724 if (c
->stream
->feed_filename
[0])
1725 url_fprintf(pb
, "<link rel=\"shortcut icon\" href=\"%s\">\n", c
->stream
->feed_filename
);
1726 url_fprintf(pb
, "</head>\n<body>");
1727 url_fprintf(pb
, "<h1>%s Status</h1>\n", program_name
);
1729 url_fprintf(pb
, "<h2>Available Streams</h2>\n");
1730 url_fprintf(pb
, "<table cellspacing=0 cellpadding=4>\n");
1731 url_fprintf(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");
1732 stream
= first_stream
;
1733 while (stream
!= NULL
) {
1734 char sfilename
[1024];
1737 if (stream
->feed
!= stream
) {
1738 av_strlcpy(sfilename
, stream
->filename
, sizeof(sfilename
) - 10);
1739 eosf
= sfilename
+ strlen(sfilename
);
1740 if (eosf
- sfilename
>= 4) {
1741 if (strcmp(eosf
- 4, ".asf") == 0)
1742 strcpy(eosf
- 4, ".asx");
1743 else if (strcmp(eosf
- 3, ".rm") == 0)
1744 strcpy(eosf
- 3, ".ram");
1745 else if (stream
->fmt
&& !strcmp(stream
->fmt
->name
, "rtp")) {
1746 /* generate a sample RTSP director if
1747 unicast. Generate an SDP redirector if
1749 eosf
= strrchr(sfilename
, '.');
1751 eosf
= sfilename
+ strlen(sfilename
);
1752 if (stream
->is_multicast
)
1753 strcpy(eosf
, ".sdp");
1755 strcpy(eosf
, ".rtsp");
1759 url_fprintf(pb
, "<tr><td><a href=\"/%s\">%s</a> ",
1760 sfilename
, stream
->filename
);
1761 url_fprintf(pb
, "<td align=right> %d <td align=right> ",
1762 stream
->conns_served
);
1763 fmt_bytecount(pb
, stream
->bytes_served
);
1764 switch(stream
->stream_type
) {
1765 case STREAM_TYPE_LIVE
: {
1766 int audio_bit_rate
= 0;
1767 int video_bit_rate
= 0;
1768 const char *audio_codec_name
= "";
1769 const char *video_codec_name
= "";
1770 const char *audio_codec_name_extra
= "";
1771 const char *video_codec_name_extra
= "";
1773 for(i
=0;i
<stream
->nb_streams
;i
++) {
1774 AVStream
*st
= stream
->streams
[i
];
1775 AVCodec
*codec
= avcodec_find_encoder(st
->codec
->codec_id
);
1776 switch(st
->codec
->codec_type
) {
1777 case CODEC_TYPE_AUDIO
:
1778 audio_bit_rate
+= st
->codec
->bit_rate
;
1780 if (*audio_codec_name
)
1781 audio_codec_name_extra
= "...";
1782 audio_codec_name
= codec
->name
;
1785 case CODEC_TYPE_VIDEO
:
1786 video_bit_rate
+= st
->codec
->bit_rate
;
1788 if (*video_codec_name
)
1789 video_codec_name_extra
= "...";
1790 video_codec_name
= codec
->name
;
1793 case CODEC_TYPE_DATA
:
1794 video_bit_rate
+= st
->codec
->bit_rate
;
1800 url_fprintf(pb
, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
1803 video_bit_rate
/ 1000, video_codec_name
, video_codec_name_extra
,
1804 audio_bit_rate
/ 1000, audio_codec_name
, audio_codec_name_extra
);
1806 url_fprintf(pb
, "<td>%s", stream
->feed
->filename
);
1808 url_fprintf(pb
, "<td>%s", stream
->feed_filename
);
1809 url_fprintf(pb
, "\n");
1813 url_fprintf(pb
, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1817 stream
= stream
->next
;
1819 url_fprintf(pb
, "</table>\n");
1821 stream
= first_stream
;
1822 while (stream
!= NULL
) {
1823 if (stream
->feed
== stream
) {
1824 url_fprintf(pb
, "<h2>Feed %s</h2>", stream
->filename
);
1826 url_fprintf(pb
, "Running as pid %d.\n", stream
->pid
);
1828 #if defined(linux) && !defined(CONFIG_NOCUTILS)
1833 /* This is somewhat linux specific I guess */
1834 snprintf(ps_cmd
, sizeof(ps_cmd
),
1835 "ps -o \"%%cpu,cputime\" --no-headers %d",
1838 pid_stat
= popen(ps_cmd
, "r");
1843 if (fscanf(pid_stat
, "%10s %64s", cpuperc
,
1845 url_fprintf(pb
, "Currently using %s%% of the cpu. Total time used %s.\n",
1853 url_fprintf(pb
, "<p>");
1855 url_fprintf(pb
, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
1857 for (i
= 0; i
< stream
->nb_streams
; i
++) {
1858 AVStream
*st
= stream
->streams
[i
];
1859 AVCodec
*codec
= avcodec_find_encoder(st
->codec
->codec_id
);
1860 const char *type
= "unknown";
1861 char parameters
[64];
1865 switch(st
->codec
->codec_type
) {
1866 case CODEC_TYPE_AUDIO
:
1868 snprintf(parameters
, sizeof(parameters
), "%d channel(s), %d Hz", st
->codec
->channels
, st
->codec
->sample_rate
);
1870 case CODEC_TYPE_VIDEO
:
1872 snprintf(parameters
, sizeof(parameters
), "%dx%d, q=%d-%d, fps=%d", st
->codec
->width
, st
->codec
->height
,
1873 st
->codec
->qmin
, st
->codec
->qmax
, st
->codec
->time_base
.den
/ st
->codec
->time_base
.num
);
1878 url_fprintf(pb
, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1879 i
, type
, st
->codec
->bit_rate
/1000, codec ? codec
->name
: "", parameters
);
1881 url_fprintf(pb
, "</table>\n");
1884 stream
= stream
->next
;
1887 /* connection status */
1888 url_fprintf(pb
, "<h2>Connection Status</h2>\n");
1890 url_fprintf(pb
, "Number of connections: %d / %d<br>\n",
1891 nb_connections
, nb_max_connections
);
1893 url_fprintf(pb
, "Bandwidth in use: %"PRIu64
"k / %"PRIu64
"k<br>\n",
1894 current_bandwidth
, max_bandwidth
);
1896 url_fprintf(pb
, "<table>\n");
1897 url_fprintf(pb
, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1898 c1
= first_http_ctx
;
1900 while (c1
!= NULL
) {
1906 for (j
= 0; j
< c1
->stream
->nb_streams
; j
++) {
1907 if (!c1
->stream
->feed
)
1908 bitrate
+= c1
->stream
->streams
[j
]->codec
->bit_rate
;
1909 else if (c1
->feed_streams
[j
] >= 0)
1910 bitrate
+= c1
->stream
->feed
->streams
[c1
->feed_streams
[j
]]->codec
->bit_rate
;
1915 p
= inet_ntoa(c1
->from_addr
.sin_addr
);
1916 url_fprintf(pb
, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1918 c1
->stream ? c1
->stream
->filename
: "",
1919 c1
->state
== HTTPSTATE_RECEIVE_DATA ?
"(input)" : "",
1922 http_state
[c1
->state
]);
1923 fmt_bytecount(pb
, bitrate
);
1924 url_fprintf(pb
, "<td align=right>");
1925 fmt_bytecount(pb
, compute_datarate(&c1
->datarate
, c1
->data_count
) * 8);
1926 url_fprintf(pb
, "<td align=right>");
1927 fmt_bytecount(pb
, c1
->data_count
);
1928 url_fprintf(pb
, "\n");
1931 url_fprintf(pb
, "</table>\n");
1936 url_fprintf(pb
, "<hr size=1 noshade>Generated at %s", p
);
1937 url_fprintf(pb
, "</body>\n</html>\n");
1939 len
= url_close_dyn_buf(pb
, &c
->pb_buffer
);
1940 c
->buffer_ptr
= c
->pb_buffer
;
1941 c
->buffer_end
= c
->pb_buffer
+ len
;
1944 /* check if the parser needs to be opened for stream i */
1945 static void open_parser(AVFormatContext
*s
, int i
)
1947 AVStream
*st
= s
->streams
[i
];
1950 if (!st
->codec
->codec
) {
1951 codec
= avcodec_find_decoder(st
->codec
->codec_id
);
1952 if (codec
&& (codec
->capabilities
& CODEC_CAP_PARSE_ONLY
)) {
1953 st
->codec
->parse_only
= 1;
1954 if (avcodec_open(st
->codec
, codec
) < 0)
1955 st
->codec
->parse_only
= 0;
1960 static int open_input_stream(HTTPContext
*c
, const char *info
)
1963 char input_filename
[1024];
1965 int buf_size
, i
, ret
;
1968 /* find file name */
1969 if (c
->stream
->feed
) {
1970 strcpy(input_filename
, c
->stream
->feed
->feed_filename
);
1971 buf_size
= FFM_PACKET_SIZE
;
1972 /* compute position (absolute time) */
1973 if (find_info_tag(buf
, sizeof(buf
), "date", info
)) {
1974 stream_pos
= parse_date(buf
, 0);
1975 if (stream_pos
== INT64_MIN
)
1977 } else if (find_info_tag(buf
, sizeof(buf
), "buffer", info
)) {
1978 int prebuffer
= strtol(buf
, 0, 10);
1979 stream_pos
= av_gettime() - prebuffer
* (int64_t)1000000;
1981 stream_pos
= av_gettime() - c
->stream
->prebuffer
* (int64_t)1000;
1983 strcpy(input_filename
, c
->stream
->feed_filename
);
1985 /* compute position (relative time) */
1986 if (find_info_tag(buf
, sizeof(buf
), "date", info
)) {
1987 stream_pos
= parse_date(buf
, 1);
1988 if (stream_pos
== INT64_MIN
)
1993 if (input_filename
[0] == '\0')
1997 if ((ret
= av_open_input_file(&s
, input_filename
, c
->stream
->ifmt
,
1998 buf_size
, c
->stream
->ap_in
)) < 0) {
1999 http_log("could not open %s: %d\n", input_filename
, ret
);
2002 s
->flags
|= AVFMT_FLAG_GENPTS
;
2004 if (strcmp(s
->iformat
->name
, "ffm") && av_find_stream_info(c
->fmt_in
) < 0) {
2005 http_log("Could not find stream info '%s'\n", input_filename
);
2006 av_close_input_file(s
);
2010 /* open each parser */
2011 for(i
=0;i
<s
->nb_streams
;i
++)
2014 /* choose stream as clock source (we favorize video stream if
2015 present) for packet sending */
2016 c
->pts_stream_index
= 0;
2017 for(i
=0;i
<c
->stream
->nb_streams
;i
++) {
2018 if (c
->pts_stream_index
== 0 &&
2019 c
->stream
->streams
[i
]->codec
->codec_type
== CODEC_TYPE_VIDEO
) {
2020 c
->pts_stream_index
= i
;
2025 if (c
->fmt_in
->iformat
->read_seek
)
2026 av_seek_frame(c
->fmt_in
, -1, stream_pos
, 0);
2028 /* set the start time (needed for maxtime and RTP packet timing) */
2029 c
->start_time
= cur_time
;
2030 c
->first_pts
= AV_NOPTS_VALUE
;
2034 /* return the server clock (in us) */
2035 static int64_t get_server_clock(HTTPContext
*c
)
2037 /* compute current pts value from system time */
2038 return (cur_time
- c
->start_time
) * 1000;
2041 /* return the estimated time at which the current packet must be sent
2043 static int64_t get_packet_send_clock(HTTPContext
*c
)
2045 int bytes_left
, bytes_sent
, frame_bytes
;
2047 frame_bytes
= c
->cur_frame_bytes
;
2048 if (frame_bytes
<= 0)
2051 bytes_left
= c
->buffer_end
- c
->buffer_ptr
;
2052 bytes_sent
= frame_bytes
- bytes_left
;
2053 return c
->cur_pts
+ (c
->cur_frame_duration
* bytes_sent
) / frame_bytes
;
2058 static int http_prepare_data(HTTPContext
*c
)
2061 AVFormatContext
*ctx
;
2063 av_freep(&c
->pb_buffer
);
2065 case HTTPSTATE_SEND_DATA_HEADER
:
2066 memset(&c
->fmt_ctx
, 0, sizeof(c
->fmt_ctx
));
2067 av_metadata_set(&c
->fmt_ctx
.metadata
, "author" ,c
->stream
->author
);
2068 av_metadata_set(&c
->fmt_ctx
.metadata
, "comment" ,c
->stream
->comment
);
2069 av_metadata_set(&c
->fmt_ctx
.metadata
, "copyright",c
->stream
->copyright
);
2070 av_metadata_set(&c
->fmt_ctx
.metadata
, "title" ,c
->stream
->title
);
2072 for(i
=0;i
<c
->stream
->nb_streams
;i
++) {
2075 st
= av_mallocz(sizeof(AVStream
));
2076 c
->fmt_ctx
.streams
[i
] = st
;
2077 /* if file or feed, then just take streams from FFStream struct */
2078 if (!c
->stream
->feed
||
2079 c
->stream
->feed
== c
->stream
)
2080 src
= c
->stream
->streams
[i
];
2082 src
= c
->stream
->feed
->streams
[c
->stream
->feed_streams
[i
]];
2086 st
->codec
->frame_number
= 0; /* XXX: should be done in
2087 AVStream, not in codec */
2089 /* set output format parameters */
2090 c
->fmt_ctx
.oformat
= c
->stream
->fmt
;
2091 c
->fmt_ctx
.nb_streams
= c
->stream
->nb_streams
;
2093 c
->got_key_frame
= 0;
2095 /* prepare header and save header data in a stream */
2096 if (url_open_dyn_buf(&c
->fmt_ctx
.pb
) < 0) {
2097 /* XXX: potential leak */
2100 c
->fmt_ctx
.pb
->is_streamed
= 1;
2103 * HACK to avoid mpeg ps muxer to spit many underflow errors
2104 * Default value from FFmpeg
2105 * Try to set it use configuration option
2107 c
->fmt_ctx
.preload
= (int)(0.5*AV_TIME_BASE
);
2108 c
->fmt_ctx
.max_delay
= (int)(0.7*AV_TIME_BASE
);
2110 av_set_parameters(&c
->fmt_ctx
, NULL
);
2111 if (av_write_header(&c
->fmt_ctx
) < 0) {
2112 http_log("Error writing output header\n");
2116 len
= url_close_dyn_buf(c
->fmt_ctx
.pb
, &c
->pb_buffer
);
2117 c
->buffer_ptr
= c
->pb_buffer
;
2118 c
->buffer_end
= c
->pb_buffer
+ len
;
2120 c
->state
= HTTPSTATE_SEND_DATA
;
2121 c
->last_packet_sent
= 0;
2123 case HTTPSTATE_SEND_DATA
:
2124 /* find a new packet */
2125 /* read a packet from the input stream */
2126 if (c
->stream
->feed
)
2127 ffm_set_write_index(c
->fmt_in
,
2128 c
->stream
->feed
->feed_write_index
,
2129 c
->stream
->feed
->feed_size
);
2131 if (c
->stream
->max_time
&&
2132 c
->stream
->max_time
+ c
->start_time
- cur_time
< 0)
2133 /* We have timed out */
2134 c
->state
= HTTPSTATE_SEND_DATA_TRAILER
;
2138 if (av_read_frame(c
->fmt_in
, &pkt
) < 0) {
2139 if (c
->stream
->feed
&& c
->stream
->feed
->feed_opened
) {
2140 /* if coming from feed, it means we reached the end of the
2141 ffm file, so must wait for more data */
2142 c
->state
= HTTPSTATE_WAIT_FEED
;
2143 return 1; /* state changed */
2145 if (c
->stream
->loop
) {
2146 av_close_input_file(c
->fmt_in
);
2148 if (open_input_stream(c
, "") < 0)
2153 /* must send trailer now because eof or error */
2154 c
->state
= HTTPSTATE_SEND_DATA_TRAILER
;
2158 int source_index
= pkt
.stream_index
;
2159 /* update first pts if needed */
2160 if (c
->first_pts
== AV_NOPTS_VALUE
) {
2161 c
->first_pts
= av_rescale_q(pkt
.dts
, c
->fmt_in
->streams
[pkt
.stream_index
]->time_base
, AV_TIME_BASE_Q
);
2162 c
->start_time
= cur_time
;
2164 /* send it to the appropriate stream */
2165 if (c
->stream
->feed
) {
2166 /* if coming from a feed, select the right stream */
2167 if (c
->switch_pending
) {
2168 c
->switch_pending
= 0;
2169 for(i
=0;i
<c
->stream
->nb_streams
;i
++) {
2170 if (c
->switch_feed_streams
[i
] == pkt
.stream_index
)
2171 if (pkt
.flags
& PKT_FLAG_KEY
)
2172 do_switch_stream(c
, i
);
2173 if (c
->switch_feed_streams
[i
] >= 0)
2174 c
->switch_pending
= 1;
2177 for(i
=0;i
<c
->stream
->nb_streams
;i
++) {
2178 if (c
->feed_streams
[i
] == pkt
.stream_index
) {
2179 AVStream
*st
= c
->fmt_in
->streams
[source_index
];
2180 pkt
.stream_index
= i
;
2181 if (pkt
.flags
& PKT_FLAG_KEY
&&
2182 (st
->codec
->codec_type
== CODEC_TYPE_VIDEO
||
2183 c
->stream
->nb_streams
== 1))
2184 c
->got_key_frame
= 1;
2185 if (!c
->stream
->send_on_key
|| c
->got_key_frame
)
2190 AVCodecContext
*codec
;
2191 AVStream
*ist
, *ost
;
2193 ist
= c
->fmt_in
->streams
[source_index
];
2194 /* specific handling for RTP: we use several
2195 output stream (one for each RTP
2196 connection). XXX: need more abstract handling */
2197 if (c
->is_packetized
) {
2198 /* compute send time and duration */
2199 c
->cur_pts
= av_rescale_q(pkt
.dts
, ist
->time_base
, AV_TIME_BASE_Q
);
2200 if (ist
->start_time
!= AV_NOPTS_VALUE
)
2201 c
->cur_pts
-= av_rescale_q(ist
->start_time
, ist
->time_base
, AV_TIME_BASE_Q
);
2202 c
->cur_frame_duration
= av_rescale_q(pkt
.duration
, ist
->time_base
, AV_TIME_BASE_Q
);
2203 /* find RTP context */
2204 c
->packet_stream_index
= pkt
.stream_index
;
2205 ctx
= c
->rtp_ctx
[c
->packet_stream_index
];
2207 av_free_packet(&pkt
);
2210 codec
= ctx
->streams
[0]->codec
;
2211 /* only one stream per RTP connection */
2212 pkt
.stream_index
= 0;
2216 codec
= ctx
->streams
[pkt
.stream_index
]->codec
;
2219 if (c
->is_packetized
) {
2220 int max_packet_size
;
2221 if (c
->rtp_protocol
== RTSP_LOWER_TRANSPORT_TCP
)
2222 max_packet_size
= RTSP_TCP_MAX_PACKET_SIZE
;
2224 max_packet_size
= url_get_max_packet_size(c
->rtp_handles
[c
->packet_stream_index
]);
2225 ret
= url_open_dyn_packet_buf(&ctx
->pb
, max_packet_size
);
2227 ret
= url_open_dyn_buf(&ctx
->pb
);
2230 /* XXX: potential leak */
2233 ost
= ctx
->streams
[pkt
.stream_index
];
2235 ctx
->pb
->is_streamed
= 1;
2236 if (pkt
.dts
!= AV_NOPTS_VALUE
)
2237 pkt
.dts
= av_rescale_q(pkt
.dts
, ist
->time_base
, ost
->time_base
);
2238 if (pkt
.pts
!= AV_NOPTS_VALUE
)
2239 pkt
.pts
= av_rescale_q(pkt
.pts
, ist
->time_base
, ost
->time_base
);
2240 pkt
.duration
= av_rescale_q(pkt
.duration
, ist
->time_base
, ost
->time_base
);
2241 if (av_write_frame(ctx
, &pkt
) < 0) {
2242 http_log("Error writing frame to output\n");
2243 c
->state
= HTTPSTATE_SEND_DATA_TRAILER
;
2246 len
= url_close_dyn_buf(ctx
->pb
, &c
->pb_buffer
);
2247 c
->cur_frame_bytes
= len
;
2248 c
->buffer_ptr
= c
->pb_buffer
;
2249 c
->buffer_end
= c
->pb_buffer
+ len
;
2251 codec
->frame_number
++;
2253 av_free_packet(&pkt
);
2257 av_free_packet(&pkt
);
2262 case HTTPSTATE_SEND_DATA_TRAILER
:
2263 /* last packet test ? */
2264 if (c
->last_packet_sent
|| c
->is_packetized
)
2267 /* prepare header */
2268 if (url_open_dyn_buf(&ctx
->pb
) < 0) {
2269 /* XXX: potential leak */
2272 c
->fmt_ctx
.pb
->is_streamed
= 1;
2273 av_write_trailer(ctx
);
2274 len
= url_close_dyn_buf(ctx
->pb
, &c
->pb_buffer
);
2275 c
->buffer_ptr
= c
->pb_buffer
;
2276 c
->buffer_end
= c
->pb_buffer
+ len
;
2278 c
->last_packet_sent
= 1;
2284 /* should convert the format at the same time */
2285 /* send data starting at c->buffer_ptr to the output connection
2286 (either UDP or TCP connection) */
2287 static int http_send_data(HTTPContext
*c
)
2292 if (c
->buffer_ptr
>= c
->buffer_end
) {
2293 ret
= http_prepare_data(c
);
2297 /* state change requested */
2300 if (c
->is_packetized
) {
2301 /* RTP data output */
2302 len
= c
->buffer_end
- c
->buffer_ptr
;
2304 /* fail safe - should never happen */
2306 c
->buffer_ptr
= c
->buffer_end
;
2309 len
= (c
->buffer_ptr
[0] << 24) |
2310 (c
->buffer_ptr
[1] << 16) |
2311 (c
->buffer_ptr
[2] << 8) |
2313 if (len
> (c
->buffer_end
- c
->buffer_ptr
))
2315 if ((get_packet_send_clock(c
) - get_server_clock(c
)) > 0) {
2316 /* nothing to send yet: we can wait */
2320 c
->data_count
+= len
;
2321 update_datarate(&c
->datarate
, c
->data_count
);
2323 c
->stream
->bytes_served
+= len
;
2325 if (c
->rtp_protocol
== RTSP_LOWER_TRANSPORT_TCP
) {
2326 /* RTP packets are sent inside the RTSP TCP connection */
2328 int interleaved_index
, size
;
2330 HTTPContext
*rtsp_c
;
2333 /* if no RTSP connection left, error */
2336 /* if already sending something, then wait. */
2337 if (rtsp_c
->state
!= RTSPSTATE_WAIT_REQUEST
)
2339 if (url_open_dyn_buf(&pb
) < 0)
2341 interleaved_index
= c
->packet_stream_index
* 2;
2342 /* RTCP packets are sent at odd indexes */
2343 if (c
->buffer_ptr
[1] == 200)
2344 interleaved_index
++;
2345 /* write RTSP TCP header */
2347 header
[1] = interleaved_index
;
2348 header
[2] = len
>> 8;
2350 put_buffer(pb
, header
, 4);
2351 /* write RTP packet data */
2353 put_buffer(pb
, c
->buffer_ptr
, len
);
2354 size
= url_close_dyn_buf(pb
, &c
->packet_buffer
);
2355 /* prepare asynchronous TCP sending */
2356 rtsp_c
->packet_buffer_ptr
= c
->packet_buffer
;
2357 rtsp_c
->packet_buffer_end
= c
->packet_buffer
+ size
;
2358 c
->buffer_ptr
+= len
;
2360 /* send everything we can NOW */
2361 len
= send(rtsp_c
->fd
, rtsp_c
->packet_buffer_ptr
,
2362 rtsp_c
->packet_buffer_end
- rtsp_c
->packet_buffer_ptr
, 0);
2364 rtsp_c
->packet_buffer_ptr
+= len
;
2365 if (rtsp_c
->packet_buffer_ptr
< rtsp_c
->packet_buffer_end
) {
2366 /* if we could not send all the data, we will
2367 send it later, so a new state is needed to
2368 "lock" the RTSP TCP connection */
2369 rtsp_c
->state
= RTSPSTATE_SEND_PACKET
;
2372 /* all data has been sent */
2373 av_freep(&c
->packet_buffer
);
2375 /* send RTP packet directly in UDP */
2377 url_write(c
->rtp_handles
[c
->packet_stream_index
],
2378 c
->buffer_ptr
, len
);
2379 c
->buffer_ptr
+= len
;
2380 /* here we continue as we can send several packets per 10 ms slot */
2383 /* TCP data output */
2384 len
= send(c
->fd
, c
->buffer_ptr
, c
->buffer_end
- c
->buffer_ptr
, 0);
2386 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
2387 ff_neterrno() != FF_NETERROR(EINTR
))
2388 /* error : close connection */
2393 c
->buffer_ptr
+= len
;
2395 c
->data_count
+= len
;
2396 update_datarate(&c
->datarate
, c
->data_count
);
2398 c
->stream
->bytes_served
+= len
;
2406 static int http_start_receive_data(HTTPContext
*c
)
2410 if (c
->stream
->feed_opened
)
2413 /* Don't permit writing to this one */
2414 if (c
->stream
->readonly
)
2418 fd
= open(c
->stream
->feed_filename
, O_RDWR
);
2420 http_log("Error opening feeder file: %s\n", strerror(errno
));
2425 if (c
->stream
->truncate
) {
2426 /* truncate feed file */
2427 ffm_write_write_index(c
->feed_fd
, FFM_PACKET_SIZE
);
2428 ftruncate(c
->feed_fd
, FFM_PACKET_SIZE
);
2429 http_log("Truncating feed file '%s'\n", c
->stream
->feed_filename
);
2431 if ((c
->stream
->feed_write_index
= ffm_read_write_index(fd
)) < 0) {
2432 http_log("Error reading write index from feed file: %s\n", strerror(errno
));
2437 c
->stream
->feed_write_index
= FFMAX(ffm_read_write_index(fd
), FFM_PACKET_SIZE
);
2438 c
->stream
->feed_size
= lseek(fd
, 0, SEEK_END
);
2439 lseek(fd
, 0, SEEK_SET
);
2441 /* init buffer input */
2442 c
->buffer_ptr
= c
->buffer
;
2443 c
->buffer_end
= c
->buffer
+ FFM_PACKET_SIZE
;
2444 c
->stream
->feed_opened
= 1;
2445 c
->chunked_encoding
= !!av_stristr(c
->buffer
, "Transfer-Encoding: chunked");
2449 static int http_receive_data(HTTPContext
*c
)
2452 int len
, loop_run
= 0;
2454 while (c
->chunked_encoding
&& !c
->chunk_size
&&
2455 c
->buffer_end
> c
->buffer_ptr
) {
2456 /* read chunk header, if present */
2457 len
= recv(c
->fd
, c
->buffer_ptr
, 1, 0);
2460 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
2461 ff_neterrno() != FF_NETERROR(EINTR
))
2462 /* error : close connection */
2464 } else if (len
== 0) {
2465 /* end of connection : close it */
2467 } else if (c
->buffer_ptr
- c
->buffer
>= 2 &&
2468 !memcmp(c
->buffer_ptr
- 1, "\r\n", 2)) {
2469 c
->chunk_size
= strtol(c
->buffer
, 0, 16);
2470 if (c
->chunk_size
== 0) // end of stream
2472 c
->buffer_ptr
= c
->buffer
;
2474 } else if (++loop_run
> 10) {
2475 /* no chunk header, abort */
2482 if (c
->buffer_end
> c
->buffer_ptr
) {
2483 len
= recv(c
->fd
, c
->buffer_ptr
,
2484 FFMIN(c
->chunk_size
, c
->buffer_end
- c
->buffer_ptr
), 0);
2486 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
2487 ff_neterrno() != FF_NETERROR(EINTR
))
2488 /* error : close connection */
2490 } else if (len
== 0)
2491 /* end of connection : close it */
2494 c
->chunk_size
-= len
;
2495 c
->buffer_ptr
+= len
;
2496 c
->data_count
+= len
;
2497 update_datarate(&c
->datarate
, c
->data_count
);
2501 if (c
->buffer_ptr
- c
->buffer
>= 2 && c
->data_count
> FFM_PACKET_SIZE
) {
2502 if (c
->buffer
[0] != 'f' ||
2503 c
->buffer
[1] != 'm') {
2504 http_log("Feed stream has become desynchronized -- disconnecting\n");
2509 if (c
->buffer_ptr
>= c
->buffer_end
) {
2510 FFStream
*feed
= c
->stream
;
2511 /* a packet has been received : write it in the store, except
2513 if (c
->data_count
> FFM_PACKET_SIZE
) {
2515 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2516 /* XXX: use llseek or url_seek */
2517 lseek(c
->feed_fd
, feed
->feed_write_index
, SEEK_SET
);
2518 if (write(c
->feed_fd
, c
->buffer
, FFM_PACKET_SIZE
) < 0) {
2519 http_log("Error writing to feed file: %s\n", strerror(errno
));
2523 feed
->feed_write_index
+= FFM_PACKET_SIZE
;
2524 /* update file size */
2525 if (feed
->feed_write_index
> c
->stream
->feed_size
)
2526 feed
->feed_size
= feed
->feed_write_index
;
2528 /* handle wrap around if max file size reached */
2529 if (c
->stream
->feed_max_size
&& feed
->feed_write_index
>= c
->stream
->feed_max_size
)
2530 feed
->feed_write_index
= FFM_PACKET_SIZE
;
2533 if (ffm_write_write_index(c
->feed_fd
, feed
->feed_write_index
) < 0) {
2534 http_log("Error writing index to feed file: %s\n", strerror(errno
));
2538 /* wake up any waiting connections */
2539 for(c1
= first_http_ctx
; c1
!= NULL
; c1
= c1
->next
) {
2540 if (c1
->state
== HTTPSTATE_WAIT_FEED
&&
2541 c1
->stream
->feed
== c
->stream
->feed
)
2542 c1
->state
= HTTPSTATE_SEND_DATA
;
2545 /* We have a header in our hands that contains useful data */
2546 AVFormatContext
*s
= NULL
;
2548 AVInputFormat
*fmt_in
;
2551 /* use feed output format name to find corresponding input format */
2552 fmt_in
= av_find_input_format(feed
->fmt
->name
);
2556 url_open_buf(&pb
, c
->buffer
, c
->buffer_end
- c
->buffer
, URL_RDONLY
);
2557 pb
->is_streamed
= 1;
2559 if (av_open_input_stream(&s
, pb
, c
->stream
->feed_filename
, fmt_in
, NULL
) < 0) {
2564 /* Now we have the actual streams */
2565 if (s
->nb_streams
!= feed
->nb_streams
) {
2566 av_close_input_stream(s
);
2568 http_log("Feed '%s' stream number does not match registered feed\n",
2569 c
->stream
->feed_filename
);
2573 for (i
= 0; i
< s
->nb_streams
; i
++) {
2574 AVStream
*fst
= feed
->streams
[i
];
2575 AVStream
*st
= s
->streams
[i
];
2576 memcpy(fst
->codec
, st
->codec
, sizeof(AVCodecContext
));
2577 if (fst
->codec
->extradata_size
) {
2578 fst
->codec
->extradata
= av_malloc(fst
->codec
->extradata_size
);
2579 if (!fst
->codec
->extradata
)
2581 memcpy(fst
->codec
->extradata
, st
->codec
->extradata
,
2582 fst
->codec
->extradata_size
);
2586 av_close_input_stream(s
);
2589 c
->buffer_ptr
= c
->buffer
;
2594 c
->stream
->feed_opened
= 0;
2596 /* wake up any waiting connections to stop waiting for feed */
2597 for(c1
= first_http_ctx
; c1
!= NULL
; c1
= c1
->next
) {
2598 if (c1
->state
== HTTPSTATE_WAIT_FEED
&&
2599 c1
->stream
->feed
== c
->stream
->feed
)
2600 c1
->state
= HTTPSTATE_SEND_DATA_TRAILER
;
2605 /********************************************************************/
2608 static void rtsp_reply_header(HTTPContext
*c
, enum RTSPStatusCode error_number
)
2615 switch(error_number
) {
2616 case RTSP_STATUS_OK
:
2619 case RTSP_STATUS_METHOD
:
2620 str
= "Method Not Allowed";
2622 case RTSP_STATUS_BANDWIDTH
:
2623 str
= "Not Enough Bandwidth";
2625 case RTSP_STATUS_SESSION
:
2626 str
= "Session Not Found";
2628 case RTSP_STATUS_STATE
:
2629 str
= "Method Not Valid in This State";
2631 case RTSP_STATUS_AGGREGATE
:
2632 str
= "Aggregate operation not allowed";
2634 case RTSP_STATUS_ONLY_AGGREGATE
:
2635 str
= "Only aggregate operation allowed";
2637 case RTSP_STATUS_TRANSPORT
:
2638 str
= "Unsupported transport";
2640 case RTSP_STATUS_INTERNAL
:
2641 str
= "Internal Server Error";
2643 case RTSP_STATUS_SERVICE
:
2644 str
= "Service Unavailable";
2646 case RTSP_STATUS_VERSION
:
2647 str
= "RTSP Version not supported";
2650 str
= "Unknown Error";
2654 url_fprintf(c
->pb
, "RTSP/1.0 %d %s\r\n", error_number
, str
);
2655 url_fprintf(c
->pb
, "CSeq: %d\r\n", c
->seq
);
2657 /* output GMT time */
2661 p
= buf2
+ strlen(p
) - 1;
2664 url_fprintf(c
->pb
, "Date: %s GMT\r\n", buf2
);
2667 static void rtsp_reply_error(HTTPContext
*c
, enum RTSPStatusCode error_number
)
2669 rtsp_reply_header(c
, error_number
);
2670 url_fprintf(c
->pb
, "\r\n");
2673 static int rtsp_parse_request(HTTPContext
*c
)
2675 const char *p
, *p1
, *p2
;
2681 RTSPMessageHeader header1
, *header
= &header1
;
2683 c
->buffer_ptr
[0] = '\0';
2686 get_word(cmd
, sizeof(cmd
), &p
);
2687 get_word(url
, sizeof(url
), &p
);
2688 get_word(protocol
, sizeof(protocol
), &p
);
2690 av_strlcpy(c
->method
, cmd
, sizeof(c
->method
));
2691 av_strlcpy(c
->url
, url
, sizeof(c
->url
));
2692 av_strlcpy(c
->protocol
, protocol
, sizeof(c
->protocol
));
2694 if (url_open_dyn_buf(&c
->pb
) < 0) {
2695 /* XXX: cannot do more */
2696 c
->pb
= NULL
; /* safety */
2700 /* check version name */
2701 if (strcmp(protocol
, "RTSP/1.0") != 0) {
2702 rtsp_reply_error(c
, RTSP_STATUS_VERSION
);
2706 /* parse each header line */
2707 memset(header
, 0, sizeof(*header
));
2708 /* skip to next line */
2709 while (*p
!= '\n' && *p
!= '\0')
2713 while (*p
!= '\0') {
2714 p1
= strchr(p
, '\n');
2718 if (p2
> p
&& p2
[-1] == '\r')
2720 /* skip empty line */
2724 if (len
> sizeof(line
) - 1)
2725 len
= sizeof(line
) - 1;
2726 memcpy(line
, p
, len
);
2728 ff_rtsp_parse_line(header
, line
);
2732 /* handle sequence number */
2733 c
->seq
= header
->seq
;
2735 if (!strcmp(cmd
, "DESCRIBE"))
2736 rtsp_cmd_describe(c
, url
);
2737 else if (!strcmp(cmd
, "OPTIONS"))
2738 rtsp_cmd_options(c
, url
);
2739 else if (!strcmp(cmd
, "SETUP"))
2740 rtsp_cmd_setup(c
, url
, header
);
2741 else if (!strcmp(cmd
, "PLAY"))
2742 rtsp_cmd_play(c
, url
, header
);
2743 else if (!strcmp(cmd
, "PAUSE"))
2744 rtsp_cmd_pause(c
, url
, header
);
2745 else if (!strcmp(cmd
, "TEARDOWN"))
2746 rtsp_cmd_teardown(c
, url
, header
);
2748 rtsp_reply_error(c
, RTSP_STATUS_METHOD
);
2751 len
= url_close_dyn_buf(c
->pb
, &c
->pb_buffer
);
2752 c
->pb
= NULL
; /* safety */
2754 /* XXX: cannot do more */
2757 c
->buffer_ptr
= c
->pb_buffer
;
2758 c
->buffer_end
= c
->pb_buffer
+ len
;
2759 c
->state
= RTSPSTATE_SEND_REPLY
;
2763 static int prepare_sdp_description(FFStream
*stream
, uint8_t **pbuffer
,
2764 struct in_addr my_ip
)
2766 AVFormatContext
*avc
;
2767 AVStream avs
[MAX_STREAMS
];
2770 avc
= avformat_alloc_context();
2774 av_metadata_set(&avc
->metadata
, "title",
2775 stream
->title
[0] ? stream
->title
: "No Title");
2776 avc
->nb_streams
= stream
->nb_streams
;
2777 if (stream
->is_multicast
) {
2778 snprintf(avc
->filename
, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2779 inet_ntoa(stream
->multicast_ip
),
2780 stream
->multicast_port
, stream
->multicast_ttl
);
2783 for(i
= 0; i
< stream
->nb_streams
; i
++) {
2784 avc
->streams
[i
] = &avs
[i
];
2785 avc
->streams
[i
]->codec
= stream
->streams
[i
]->codec
;
2787 *pbuffer
= av_mallocz(2048);
2788 avf_sdp_create(&avc
, 1, *pbuffer
, 2048);
2791 return strlen(*pbuffer
);
2794 static void rtsp_cmd_options(HTTPContext
*c
, const char *url
)
2796 // rtsp_reply_header(c, RTSP_STATUS_OK);
2797 url_fprintf(c
->pb
, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK
, "OK");
2798 url_fprintf(c
->pb
, "CSeq: %d\r\n", c
->seq
);
2799 url_fprintf(c
->pb
, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2800 url_fprintf(c
->pb
, "\r\n");
2803 static void rtsp_cmd_describe(HTTPContext
*c
, const char *url
)
2809 int content_length
, len
;
2810 struct sockaddr_in my_addr
;
2812 /* find which url is asked */
2813 url_split(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, path1
, sizeof(path1
), url
);
2818 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
2819 if (!stream
->is_feed
&&
2820 stream
->fmt
&& !strcmp(stream
->fmt
->name
, "rtp") &&
2821 !strcmp(path
, stream
->filename
)) {
2825 /* no stream found */
2826 rtsp_reply_error(c
, RTSP_STATUS_SERVICE
); /* XXX: right error ? */
2830 /* prepare the media description in sdp format */
2832 /* get the host IP */
2833 len
= sizeof(my_addr
);
2834 getsockname(c
->fd
, (struct sockaddr
*)&my_addr
, &len
);
2835 content_length
= prepare_sdp_description(stream
, &content
, my_addr
.sin_addr
);
2836 if (content_length
< 0) {
2837 rtsp_reply_error(c
, RTSP_STATUS_INTERNAL
);
2840 rtsp_reply_header(c
, RTSP_STATUS_OK
);
2841 url_fprintf(c
->pb
, "Content-Type: application/sdp\r\n");
2842 url_fprintf(c
->pb
, "Content-Length: %d\r\n", content_length
);
2843 url_fprintf(c
->pb
, "\r\n");
2844 put_buffer(c
->pb
, content
, content_length
);
2847 static HTTPContext
*find_rtp_session(const char *session_id
)
2851 if (session_id
[0] == '\0')
2854 for(c
= first_http_ctx
; c
!= NULL
; c
= c
->next
) {
2855 if (!strcmp(c
->session_id
, session_id
))
2861 static RTSPTransportField
*find_transport(RTSPMessageHeader
*h
, enum RTSPLowerTransport lower_transport
)
2863 RTSPTransportField
*th
;
2866 for(i
=0;i
<h
->nb_transports
;i
++) {
2867 th
= &h
->transports
[i
];
2868 if (th
->lower_transport
== lower_transport
)
2874 static void rtsp_cmd_setup(HTTPContext
*c
, const char *url
,
2875 RTSPMessageHeader
*h
)
2878 int stream_index
, port
;
2883 RTSPTransportField
*th
;
2884 struct sockaddr_in dest_addr
;
2885 RTSPActionServerSetup setup
;
2887 /* find which url is asked */
2888 url_split(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, path1
, sizeof(path1
), url
);
2893 /* now check each stream */
2894 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
2895 if (!stream
->is_feed
&&
2896 stream
->fmt
&& !strcmp(stream
->fmt
->name
, "rtp")) {
2897 /* accept aggregate filenames only if single stream */
2898 if (!strcmp(path
, stream
->filename
)) {
2899 if (stream
->nb_streams
!= 1) {
2900 rtsp_reply_error(c
, RTSP_STATUS_AGGREGATE
);
2907 for(stream_index
= 0; stream_index
< stream
->nb_streams
;
2909 snprintf(buf
, sizeof(buf
), "%s/streamid=%d",
2910 stream
->filename
, stream_index
);
2911 if (!strcmp(path
, buf
))
2916 /* no stream found */
2917 rtsp_reply_error(c
, RTSP_STATUS_SERVICE
); /* XXX: right error ? */
2921 /* generate session id if needed */
2922 if (h
->session_id
[0] == '\0')
2923 snprintf(h
->session_id
, sizeof(h
->session_id
), "%08x%08x",
2924 av_lfg_get(&random_state
), av_lfg_get(&random_state
));
2926 /* find rtp session, and create it if none found */
2927 rtp_c
= find_rtp_session(h
->session_id
);
2929 /* always prefer UDP */
2930 th
= find_transport(h
, RTSP_LOWER_TRANSPORT_UDP
);
2932 th
= find_transport(h
, RTSP_LOWER_TRANSPORT_TCP
);
2934 rtsp_reply_error(c
, RTSP_STATUS_TRANSPORT
);
2939 rtp_c
= rtp_new_connection(&c
->from_addr
, stream
, h
->session_id
,
2940 th
->lower_transport
);
2942 rtsp_reply_error(c
, RTSP_STATUS_BANDWIDTH
);
2946 /* open input stream */
2947 if (open_input_stream(rtp_c
, "") < 0) {
2948 rtsp_reply_error(c
, RTSP_STATUS_INTERNAL
);
2953 /* test if stream is OK (test needed because several SETUP needs
2954 to be done for a given file) */
2955 if (rtp_c
->stream
!= stream
) {
2956 rtsp_reply_error(c
, RTSP_STATUS_SERVICE
);
2960 /* test if stream is already set up */
2961 if (rtp_c
->rtp_ctx
[stream_index
]) {
2962 rtsp_reply_error(c
, RTSP_STATUS_STATE
);
2966 /* check transport */
2967 th
= find_transport(h
, rtp_c
->rtp_protocol
);
2968 if (!th
|| (th
->lower_transport
== RTSP_LOWER_TRANSPORT_UDP
&&
2969 th
->client_port_min
<= 0)) {
2970 rtsp_reply_error(c
, RTSP_STATUS_TRANSPORT
);
2974 /* setup default options */
2975 setup
.transport_option
[0] = '\0';
2976 dest_addr
= rtp_c
->from_addr
;
2977 dest_addr
.sin_port
= htons(th
->client_port_min
);
2980 if (rtp_new_av_stream(rtp_c
, stream_index
, &dest_addr
, c
) < 0) {
2981 rtsp_reply_error(c
, RTSP_STATUS_TRANSPORT
);
2985 /* now everything is OK, so we can send the connection parameters */
2986 rtsp_reply_header(c
, RTSP_STATUS_OK
);
2988 url_fprintf(c
->pb
, "Session: %s\r\n", rtp_c
->session_id
);
2990 switch(rtp_c
->rtp_protocol
) {
2991 case RTSP_LOWER_TRANSPORT_UDP
:
2992 port
= rtp_get_local_port(rtp_c
->rtp_handles
[stream_index
]);
2993 url_fprintf(c
->pb
, "Transport: RTP/AVP/UDP;unicast;"
2994 "client_port=%d-%d;server_port=%d-%d",
2995 th
->client_port_min
, th
->client_port_min
+ 1,
2998 case RTSP_LOWER_TRANSPORT_TCP
:
2999 url_fprintf(c
->pb
, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3000 stream_index
* 2, stream_index
* 2 + 1);
3005 if (setup
.transport_option
[0] != '\0')
3006 url_fprintf(c
->pb
, ";%s", setup
.transport_option
);
3007 url_fprintf(c
->pb
, "\r\n");
3010 url_fprintf(c
->pb
, "\r\n");
3014 /* find an rtp connection by using the session ID. Check consistency
3016 static HTTPContext
*find_rtp_session_with_url(const char *url
,
3017 const char *session_id
)
3025 rtp_c
= find_rtp_session(session_id
);
3029 /* find which url is asked */
3030 url_split(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, path1
, sizeof(path1
), url
);
3034 if(!strcmp(path
, rtp_c
->stream
->filename
)) return rtp_c
;
3035 for(s
=0; s
<rtp_c
->stream
->nb_streams
; ++s
) {
3036 snprintf(buf
, sizeof(buf
), "%s/streamid=%d",
3037 rtp_c
->stream
->filename
, s
);
3038 if(!strncmp(path
, buf
, sizeof(buf
))) {
3039 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3046 static void rtsp_cmd_play(HTTPContext
*c
, const char *url
, RTSPMessageHeader
*h
)
3050 rtp_c
= find_rtp_session_with_url(url
, h
->session_id
);
3052 rtsp_reply_error(c
, RTSP_STATUS_SESSION
);
3056 if (rtp_c
->state
!= HTTPSTATE_SEND_DATA
&&
3057 rtp_c
->state
!= HTTPSTATE_WAIT_FEED
&&
3058 rtp_c
->state
!= HTTPSTATE_READY
) {
3059 rtsp_reply_error(c
, RTSP_STATUS_STATE
);
3063 rtp_c
->state
= HTTPSTATE_SEND_DATA
;
3065 /* now everything is OK, so we can send the connection parameters */
3066 rtsp_reply_header(c
, RTSP_STATUS_OK
);
3068 url_fprintf(c
->pb
, "Session: %s\r\n", rtp_c
->session_id
);
3069 url_fprintf(c
->pb
, "\r\n");
3072 static void rtsp_cmd_pause(HTTPContext
*c
, const char *url
, RTSPMessageHeader
*h
)
3076 rtp_c
= find_rtp_session_with_url(url
, h
->session_id
);
3078 rtsp_reply_error(c
, RTSP_STATUS_SESSION
);
3082 if (rtp_c
->state
!= HTTPSTATE_SEND_DATA
&&
3083 rtp_c
->state
!= HTTPSTATE_WAIT_FEED
) {
3084 rtsp_reply_error(c
, RTSP_STATUS_STATE
);
3088 rtp_c
->state
= HTTPSTATE_READY
;
3089 rtp_c
->first_pts
= AV_NOPTS_VALUE
;
3090 /* now everything is OK, so we can send the connection parameters */
3091 rtsp_reply_header(c
, RTSP_STATUS_OK
);
3093 url_fprintf(c
->pb
, "Session: %s\r\n", rtp_c
->session_id
);
3094 url_fprintf(c
->pb
, "\r\n");
3097 static void rtsp_cmd_teardown(HTTPContext
*c
, const char *url
, RTSPMessageHeader
*h
)
3100 char session_id
[32];
3102 rtp_c
= find_rtp_session_with_url(url
, h
->session_id
);
3104 rtsp_reply_error(c
, RTSP_STATUS_SESSION
);
3108 av_strlcpy(session_id
, rtp_c
->session_id
, sizeof(session_id
));
3110 /* abort the session */
3111 close_connection(rtp_c
);
3113 /* now everything is OK, so we can send the connection parameters */
3114 rtsp_reply_header(c
, RTSP_STATUS_OK
);
3116 url_fprintf(c
->pb
, "Session: %s\r\n", session_id
);
3117 url_fprintf(c
->pb
, "\r\n");
3121 /********************************************************************/
3124 static HTTPContext
*rtp_new_connection(struct sockaddr_in
*from_addr
,
3125 FFStream
*stream
, const char *session_id
,
3126 enum RTSPLowerTransport rtp_protocol
)
3128 HTTPContext
*c
= NULL
;
3129 const char *proto_str
;
3131 /* XXX: should output a warning page when coming
3132 close to the connection limit */
3133 if (nb_connections
>= nb_max_connections
)
3136 /* add a new connection */
3137 c
= av_mallocz(sizeof(HTTPContext
));
3142 c
->poll_entry
= NULL
;
3143 c
->from_addr
= *from_addr
;
3144 c
->buffer_size
= IOBUFFER_INIT_SIZE
;
3145 c
->buffer
= av_malloc(c
->buffer_size
);
3150 av_strlcpy(c
->session_id
, session_id
, sizeof(c
->session_id
));
3151 c
->state
= HTTPSTATE_READY
;
3152 c
->is_packetized
= 1;
3153 c
->rtp_protocol
= rtp_protocol
;
3155 /* protocol is shown in statistics */
3156 switch(c
->rtp_protocol
) {
3157 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST
:
3158 proto_str
= "MCAST";
3160 case RTSP_LOWER_TRANSPORT_UDP
:
3163 case RTSP_LOWER_TRANSPORT_TCP
:
3170 av_strlcpy(c
->protocol
, "RTP/", sizeof(c
->protocol
));
3171 av_strlcat(c
->protocol
, proto_str
, sizeof(c
->protocol
));
3173 current_bandwidth
+= stream
->bandwidth
;
3175 c
->next
= first_http_ctx
;
3187 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3188 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3190 static int rtp_new_av_stream(HTTPContext
*c
,
3191 int stream_index
, struct sockaddr_in
*dest_addr
,
3192 HTTPContext
*rtsp_c
)
3194 AVFormatContext
*ctx
;
3197 URLContext
*h
= NULL
;
3199 int max_packet_size
;
3201 /* now we can open the relevant output stream */
3202 ctx
= avformat_alloc_context();
3205 ctx
->oformat
= av_guess_format("rtp", NULL
, NULL
);
3207 st
= av_mallocz(sizeof(AVStream
));
3210 st
->codec
= avcodec_alloc_context();
3211 ctx
->nb_streams
= 1;
3212 ctx
->streams
[0] = st
;
3214 if (!c
->stream
->feed
||
3215 c
->stream
->feed
== c
->stream
)
3216 memcpy(st
, c
->stream
->streams
[stream_index
], sizeof(AVStream
));
3219 c
->stream
->feed
->streams
[c
->stream
->feed_streams
[stream_index
]],
3221 st
->priv_data
= NULL
;
3223 /* build destination RTP address */
3224 ipaddr
= inet_ntoa(dest_addr
->sin_addr
);
3226 switch(c
->rtp_protocol
) {
3227 case RTSP_LOWER_TRANSPORT_UDP
:
3228 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST
:
3231 /* XXX: also pass as parameter to function ? */
3232 if (c
->stream
->is_multicast
) {
3234 ttl
= c
->stream
->multicast_ttl
;
3237 snprintf(ctx
->filename
, sizeof(ctx
->filename
),
3238 "rtp://%s:%d?multicast=1&ttl=%d",
3239 ipaddr
, ntohs(dest_addr
->sin_port
), ttl
);
3241 snprintf(ctx
->filename
, sizeof(ctx
->filename
),
3242 "rtp://%s:%d", ipaddr
, ntohs(dest_addr
->sin_port
));
3245 if (url_open(&h
, ctx
->filename
, URL_WRONLY
) < 0)
3247 c
->rtp_handles
[stream_index
] = h
;
3248 max_packet_size
= url_get_max_packet_size(h
);
3250 case RTSP_LOWER_TRANSPORT_TCP
:
3253 max_packet_size
= RTSP_TCP_MAX_PACKET_SIZE
;
3259 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3260 ipaddr
, ntohs(dest_addr
->sin_port
),
3261 c
->stream
->filename
, stream_index
, c
->protocol
);
3263 /* normally, no packets should be output here, but the packet size may be checked */
3264 if (url_open_dyn_packet_buf(&ctx
->pb
, max_packet_size
) < 0) {
3265 /* XXX: close stream */
3268 av_set_parameters(ctx
, NULL
);
3269 if (av_write_header(ctx
) < 0) {
3276 url_close_dyn_buf(ctx
->pb
, &dummy_buf
);
3279 c
->rtp_ctx
[stream_index
] = ctx
;
3283 /********************************************************************/
3284 /* ffserver initialization */
3286 static AVStream
*add_av_stream1(FFStream
*stream
, AVCodecContext
*codec
)
3290 fst
= av_mallocz(sizeof(AVStream
));
3293 fst
->codec
= avcodec_alloc_context();
3294 fst
->priv_data
= av_mallocz(sizeof(FeedData
));
3295 memcpy(fst
->codec
, codec
, sizeof(AVCodecContext
));
3296 fst
->index
= stream
->nb_streams
;
3297 av_set_pts_info(fst
, 33, 1, 90000);
3298 stream
->streams
[stream
->nb_streams
++] = fst
;
3302 /* return the stream number in the feed */
3303 static int add_av_stream(FFStream
*feed
, AVStream
*st
)
3306 AVCodecContext
*av
, *av1
;
3310 for(i
=0;i
<feed
->nb_streams
;i
++) {
3311 st
= feed
->streams
[i
];
3313 if (av1
->codec_id
== av
->codec_id
&&
3314 av1
->codec_type
== av
->codec_type
&&
3315 av1
->bit_rate
== av
->bit_rate
) {
3317 switch(av
->codec_type
) {
3318 case CODEC_TYPE_AUDIO
:
3319 if (av1
->channels
== av
->channels
&&
3320 av1
->sample_rate
== av
->sample_rate
)
3323 case CODEC_TYPE_VIDEO
:
3324 if (av1
->width
== av
->width
&&
3325 av1
->height
== av
->height
&&
3326 av1
->time_base
.den
== av
->time_base
.den
&&
3327 av1
->time_base
.num
== av
->time_base
.num
&&
3328 av1
->gop_size
== av
->gop_size
)
3337 fst
= add_av_stream1(feed
, av
);
3340 return feed
->nb_streams
- 1;
3345 static void remove_stream(FFStream
*stream
)
3349 while (*ps
!= NULL
) {
3357 /* specific mpeg4 handling : we extract the raw parameters */
3358 static void extract_mpeg4_header(AVFormatContext
*infile
)
3360 int mpeg4_count
, i
, size
;
3366 for(i
=0;i
<infile
->nb_streams
;i
++) {
3367 st
= infile
->streams
[i
];
3368 if (st
->codec
->codec_id
== CODEC_ID_MPEG4
&&
3369 st
->codec
->extradata_size
== 0) {
3376 printf("MPEG4 without extra data: trying to find header in %s\n", infile
->filename
);
3377 while (mpeg4_count
> 0) {
3378 if (av_read_packet(infile
, &pkt
) < 0)
3380 st
= infile
->streams
[pkt
.stream_index
];
3381 if (st
->codec
->codec_id
== CODEC_ID_MPEG4
&&
3382 st
->codec
->extradata_size
== 0) {
3383 av_freep(&st
->codec
->extradata
);
3384 /* fill extradata with the header */
3385 /* XXX: we make hard suppositions here ! */
3387 while (p
< pkt
.data
+ pkt
.size
- 4) {
3388 /* stop when vop header is found */
3389 if (p
[0] == 0x00 && p
[1] == 0x00 &&
3390 p
[2] == 0x01 && p
[3] == 0xb6) {
3391 size
= p
- pkt
.data
;
3392 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3393 st
->codec
->extradata
= av_malloc(size
);
3394 st
->codec
->extradata_size
= size
;
3395 memcpy(st
->codec
->extradata
, pkt
.data
, size
);
3402 av_free_packet(&pkt
);
3406 /* compute the needed AVStream for each file */
3407 static void build_file_streams(void)
3409 FFStream
*stream
, *stream_next
;
3410 AVFormatContext
*infile
;
3413 /* gather all streams */
3414 for(stream
= first_stream
; stream
!= NULL
; stream
= stream_next
) {
3415 stream_next
= stream
->next
;
3416 if (stream
->stream_type
== STREAM_TYPE_LIVE
&&
3418 /* the stream comes from a file */
3419 /* try to open the file */
3421 stream
->ap_in
= av_mallocz(sizeof(AVFormatParameters
));
3422 if (stream
->fmt
&& !strcmp(stream
->fmt
->name
, "rtp")) {
3423 /* specific case : if transport stream output to RTP,
3424 we use a raw transport stream reader */
3425 stream
->ap_in
->mpeg2ts_raw
= 1;
3426 stream
->ap_in
->mpeg2ts_compute_pcr
= 1;
3429 http_log("Opening file '%s'\n", stream
->feed_filename
);
3430 if ((ret
= av_open_input_file(&infile
, stream
->feed_filename
,
3431 stream
->ifmt
, 0, stream
->ap_in
)) < 0) {
3432 http_log("Could not open '%s': %d\n", stream
->feed_filename
, ret
);
3433 /* remove stream (no need to spend more time on it) */
3435 remove_stream(stream
);
3437 /* find all the AVStreams inside and reference them in
3439 if (av_find_stream_info(infile
) < 0) {
3440 http_log("Could not find codec parameters from '%s'\n",
3441 stream
->feed_filename
);
3442 av_close_input_file(infile
);
3445 extract_mpeg4_header(infile
);
3447 for(i
=0;i
<infile
->nb_streams
;i
++)
3448 add_av_stream1(stream
, infile
->streams
[i
]->codec
);
3450 av_close_input_file(infile
);
3456 /* compute the needed AVStream for each feed */
3457 static void build_feed_streams(void)
3459 FFStream
*stream
, *feed
;
3462 /* gather all streams */
3463 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
3464 feed
= stream
->feed
;
3466 if (!stream
->is_feed
) {
3467 /* we handle a stream coming from a feed */
3468 for(i
=0;i
<stream
->nb_streams
;i
++)
3469 stream
->feed_streams
[i
] = add_av_stream(feed
, stream
->streams
[i
]);
3474 /* gather all streams */
3475 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
3476 feed
= stream
->feed
;
3478 if (stream
->is_feed
) {
3479 for(i
=0;i
<stream
->nb_streams
;i
++)
3480 stream
->feed_streams
[i
] = i
;
3485 /* create feed files if needed */
3486 for(feed
= first_feed
; feed
!= NULL
; feed
= feed
->next_feed
) {
3489 if (url_exist(feed
->feed_filename
)) {
3490 /* See if it matches */
3494 if (av_open_input_file(&s
, feed
->feed_filename
, NULL
, FFM_PACKET_SIZE
, NULL
) >= 0) {
3495 /* Now see if it matches */
3496 if (s
->nb_streams
== feed
->nb_streams
) {
3498 for(i
=0;i
<s
->nb_streams
;i
++) {
3500 sf
= feed
->streams
[i
];
3503 if (sf
->index
!= ss
->index
||
3505 http_log("Index & Id do not match for stream %d (%s)\n",
3506 i
, feed
->feed_filename
);
3509 AVCodecContext
*ccf
, *ccs
;
3513 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3515 if (CHECK_CODEC(codec
) || CHECK_CODEC(codec_type
)) {
3516 http_log("Codecs do not match for stream %d\n", i
);
3518 } else if (CHECK_CODEC(bit_rate
) || CHECK_CODEC(flags
)) {
3519 http_log("Codec bitrates do not match for stream %d\n", i
);
3521 } else if (ccf
->codec_type
== CODEC_TYPE_VIDEO
) {
3522 if (CHECK_CODEC(time_base
.den
) ||
3523 CHECK_CODEC(time_base
.num
) ||
3524 CHECK_CODEC(width
) ||
3525 CHECK_CODEC(height
)) {
3526 http_log("Codec width, height and framerate do not match for stream %d\n", i
);
3529 } else if (ccf
->codec_type
== CODEC_TYPE_AUDIO
) {
3530 if (CHECK_CODEC(sample_rate
) ||
3531 CHECK_CODEC(channels
) ||
3532 CHECK_CODEC(frame_size
)) {
3533 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i
);
3537 http_log("Unknown codec type\n");
3545 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3546 feed
->feed_filename
, s
->nb_streams
, feed
->nb_streams
);
3548 av_close_input_file(s
);
3550 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3551 feed
->feed_filename
);
3554 if (feed
->readonly
) {
3555 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3556 feed
->feed_filename
);
3559 unlink(feed
->feed_filename
);
3562 if (!url_exist(feed
->feed_filename
)) {
3563 AVFormatContext s1
= {0}, *s
= &s1
;
3565 if (feed
->readonly
) {
3566 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3567 feed
->feed_filename
);
3571 /* only write the header of the ffm file */
3572 if (url_fopen(&s
->pb
, feed
->feed_filename
, URL_WRONLY
) < 0) {
3573 http_log("Could not open output feed file '%s'\n",
3574 feed
->feed_filename
);
3577 s
->oformat
= feed
->fmt
;
3578 s
->nb_streams
= feed
->nb_streams
;
3579 for(i
=0;i
<s
->nb_streams
;i
++) {
3581 st
= feed
->streams
[i
];
3584 av_set_parameters(s
, NULL
);
3585 if (av_write_header(s
) < 0) {
3586 http_log("Container doesn't supports the required parameters\n");
3589 /* XXX: need better api */
3590 av_freep(&s
->priv_data
);
3593 /* get feed size and write index */
3594 fd
= open(feed
->feed_filename
, O_RDONLY
);
3596 http_log("Could not open output feed file '%s'\n",
3597 feed
->feed_filename
);
3601 feed
->feed_write_index
= FFMAX(ffm_read_write_index(fd
), FFM_PACKET_SIZE
);
3602 feed
->feed_size
= lseek(fd
, 0, SEEK_END
);
3603 /* ensure that we do not wrap before the end of file */
3604 if (feed
->feed_max_size
&& feed
->feed_max_size
< feed
->feed_size
)
3605 feed
->feed_max_size
= feed
->feed_size
;
3611 /* compute the bandwidth used by each stream */
3612 static void compute_bandwidth(void)
3618 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
3620 for(i
=0;i
<stream
->nb_streams
;i
++) {
3621 AVStream
*st
= stream
->streams
[i
];
3622 switch(st
->codec
->codec_type
) {
3623 case CODEC_TYPE_AUDIO
:
3624 case CODEC_TYPE_VIDEO
:
3625 bandwidth
+= st
->codec
->bit_rate
;
3631 stream
->bandwidth
= (bandwidth
+ 999) / 1000;
3635 /* add a codec and set the default parameters */
3636 static void add_codec(FFStream
*stream
, AVCodecContext
*av
)
3640 /* compute default parameters */
3641 switch(av
->codec_type
) {
3642 case CODEC_TYPE_AUDIO
:
3643 if (av
->bit_rate
== 0)
3644 av
->bit_rate
= 64000;
3645 if (av
->sample_rate
== 0)
3646 av
->sample_rate
= 22050;
3647 if (av
->channels
== 0)
3650 case CODEC_TYPE_VIDEO
:
3651 if (av
->bit_rate
== 0)
3652 av
->bit_rate
= 64000;
3653 if (av
->time_base
.num
== 0){
3654 av
->time_base
.den
= 5;
3655 av
->time_base
.num
= 1;
3657 if (av
->width
== 0 || av
->height
== 0) {
3661 /* Bitrate tolerance is less for streaming */
3662 if (av
->bit_rate_tolerance
== 0)
3663 av
->bit_rate_tolerance
= FFMAX(av
->bit_rate
/ 4,
3664 (int64_t)av
->bit_rate
*av
->time_base
.num
/av
->time_base
.den
);
3669 if (av
->max_qdiff
== 0)
3671 av
->qcompress
= 0.5;
3674 if (!av
->nsse_weight
)
3675 av
->nsse_weight
= 8;
3677 av
->frame_skip_cmp
= FF_CMP_DCTMAX
;
3678 av
->me_method
= ME_EPZS
;
3679 av
->rc_buffer_aggressivity
= 1.0;
3682 av
->rc_eq
= "tex^qComp";
3683 if (!av
->i_quant_factor
)
3684 av
->i_quant_factor
= -0.8;
3685 if (!av
->b_quant_factor
)
3686 av
->b_quant_factor
= 1.25;
3687 if (!av
->b_quant_offset
)
3688 av
->b_quant_offset
= 1.25;
3689 if (!av
->rc_max_rate
)
3690 av
->rc_max_rate
= av
->bit_rate
* 2;
3692 if (av
->rc_max_rate
&& !av
->rc_buffer_size
) {
3693 av
->rc_buffer_size
= av
->rc_max_rate
;
3702 st
= av_mallocz(sizeof(AVStream
));
3705 st
->codec
= avcodec_alloc_context();
3706 stream
->streams
[stream
->nb_streams
++] = st
;
3707 memcpy(st
->codec
, av
, sizeof(AVCodecContext
));
3710 static enum CodecID
opt_audio_codec(const char *arg
)
3712 AVCodec
*p
= avcodec_find_encoder_by_name(arg
);
3714 if (p
== NULL
|| p
->type
!= CODEC_TYPE_AUDIO
)
3715 return CODEC_ID_NONE
;
3720 static enum CodecID
opt_video_codec(const char *arg
)
3722 AVCodec
*p
= avcodec_find_encoder_by_name(arg
);
3724 if (p
== NULL
|| p
->type
!= CODEC_TYPE_VIDEO
)
3725 return CODEC_ID_NONE
;
3730 /* simplistic plugin support */
3733 static void load_module(const char *filename
)
3736 void (*init_func
)(void);
3737 dll
= dlopen(filename
, RTLD_NOW
);
3739 fprintf(stderr
, "Could not load module '%s' - %s\n",
3740 filename
, dlerror());
3744 init_func
= dlsym(dll
, "ffserver_module_init");
3747 "%s: init function 'ffserver_module_init()' not found\n",
3756 static int ffserver_opt_default(const char *opt
, const char *arg
,
3757 AVCodecContext
*avctx
, int type
)
3760 const AVOption
*o
= av_find_opt(avctx
, opt
, NULL
, type
, type
);
3762 ret
= av_set_string3(avctx
, opt
, arg
, 1, NULL
);
3766 static AVOutputFormat
*ffserver_guess_format(const char *short_name
, const char *filename
,
3767 const char *mime_type
)