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
23 #ifndef HAVE_CLOSESOCKET
24 #define closesocket close
33 #include <sys/ioctl.h>
34 #ifdef HAVE_SYS_POLL_H
39 #undef time //needed because HAVE_AV_CONFIG_H is defined on top
55 /* maximum number of simultaneous HTTP connections */
56 #define HTTP_MAX_CONNECTIONS 2000
59 HTTPSTATE_WAIT_REQUEST
,
60 HTTPSTATE_SEND_HEADER
,
61 HTTPSTATE_SEND_DATA_HEADER
,
62 HTTPSTATE_SEND_DATA
, /* sending TCP or UDP data */
63 HTTPSTATE_SEND_DATA_TRAILER
,
64 HTTPSTATE_RECEIVE_DATA
,
65 HTTPSTATE_WAIT_FEED
, /* wait for data from the feed */
68 RTSPSTATE_WAIT_REQUEST
,
70 RTSPSTATE_SEND_PACKET
,
73 const char *http_state
[] = {
89 #define IOBUFFER_INIT_SIZE 8192
91 /* timeouts are in ms */
92 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
93 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
95 #define SYNC_TIMEOUT (10 * 1000)
98 int64_t count1
, count2
;
102 /* context associated with one connection */
103 typedef struct HTTPContext
{
104 enum HTTPState state
;
105 int fd
; /* socket file descriptor */
106 struct sockaddr_in from_addr
; /* origin */
107 struct pollfd
*poll_entry
; /* used when polling */
109 uint8_t *buffer_ptr
, *buffer_end
;
112 struct HTTPContext
*next
;
113 int got_key_frame
; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
117 /* input format handling */
118 AVFormatContext
*fmt_in
;
119 int64_t start_time
; /* In milliseconds - this wraps fairly often */
120 int64_t first_pts
; /* initial pts value */
121 int64_t cur_pts
; /* current pts value from the stream in us */
122 int64_t cur_frame_duration
; /* duration of the current frame in us */
123 int cur_frame_bytes
; /* output frame size, needed to compute
124 the time at which we send each
126 int pts_stream_index
; /* stream we choose as clock reference */
127 int64_t cur_clock
; /* current clock reference value in us */
128 /* output format handling */
129 struct FFStream
*stream
;
130 /* -1 is invalid stream */
131 int feed_streams
[MAX_STREAMS
]; /* index of streams in the feed */
132 int switch_feed_streams
[MAX_STREAMS
]; /* index of streams in the feed */
134 AVFormatContext fmt_ctx
; /* instance of FFStream for one user */
135 int last_packet_sent
; /* true if last data packet was sent */
137 DataRateData datarate
;
144 int is_packetized
; /* if true, the stream is packetized */
145 int packet_stream_index
; /* current stream for output in state machine */
147 /* RTSP state specific */
148 uint8_t *pb_buffer
; /* XXX: use that in all the code */
150 int seq
; /* RTSP sequence number */
152 /* RTP state specific */
153 enum RTSPProtocol rtp_protocol
;
154 char session_id
[32]; /* session id */
155 AVFormatContext
*rtp_ctx
[MAX_STREAMS
];
157 /* RTP/UDP specific */
158 URLContext
*rtp_handles
[MAX_STREAMS
];
160 /* RTP/TCP specific */
161 struct HTTPContext
*rtsp_c
;
162 uint8_t *packet_buffer
, *packet_buffer_ptr
, *packet_buffer_end
;
165 static AVFrame dummy_frame
;
167 /* each generated stream is described here */
171 STREAM_TYPE_REDIRECT
,
174 enum IPAddressAction
{
179 typedef struct IPAddressACL
{
180 struct IPAddressACL
*next
;
181 enum IPAddressAction action
;
182 /* These are in host order */
183 struct in_addr first
;
187 /* description of each stream of the ffserver.conf file */
188 typedef struct FFStream
{
189 enum StreamType stream_type
;
190 char filename
[1024]; /* stream filename */
191 struct FFStream
*feed
; /* feed we are using (can be null if
193 AVFormatParameters
*ap_in
; /* input parameters */
194 AVInputFormat
*ifmt
; /* if non NULL, force input format */
198 int prebuffer
; /* Number of millseconds early to start */
199 int64_t max_time
; /* Number of milliseconds to run */
201 AVStream
*streams
[MAX_STREAMS
];
202 int feed_streams
[MAX_STREAMS
]; /* index of streams in the feed */
203 char feed_filename
[1024]; /* file name of the feed storage, or
204 input file name for a stream */
209 pid_t pid
; /* Of ffmpeg process */
210 time_t pid_start
; /* Of ffmpeg process */
212 struct FFStream
*next
;
213 int bandwidth
; /* bandwidth, in kbits/s */
216 /* multicast specific */
218 struct in_addr multicast_ip
;
219 int multicast_port
; /* first port used for multicast */
221 int loop
; /* if true, send the stream in loops (only meaningful if file) */
224 int feed_opened
; /* true if someone is writing to the feed */
225 int is_feed
; /* true if it is a feed */
226 int readonly
; /* True if writing is prohibited to the file */
228 int64_t bytes_served
;
229 int64_t feed_max_size
; /* maximum storage size, zero means unlimited */
230 int64_t feed_write_index
; /* current write position in feed (it wraps round) */
231 int64_t feed_size
; /* current size of feed */
232 struct FFStream
*next_feed
;
235 typedef struct FeedData
{
236 long long data_count
;
237 float avg_frame_size
; /* frame size averraged over last frames with exponential mean */
240 static struct sockaddr_in my_http_addr
;
241 static struct sockaddr_in my_rtsp_addr
;
243 static char logfilename
[1024];
244 static HTTPContext
*first_http_ctx
;
245 static FFStream
*first_feed
; /* contains only feeds */
246 static FFStream
*first_stream
; /* contains all streams, including feeds */
248 static void new_connection(int server_fd
, int is_rtsp
);
249 static void close_connection(HTTPContext
*c
);
252 static int handle_connection(HTTPContext
*c
);
253 static int http_parse_request(HTTPContext
*c
);
254 static int http_send_data(HTTPContext
*c
);
255 static void compute_stats(HTTPContext
*c
);
256 static int open_input_stream(HTTPContext
*c
, const char *info
);
257 static int http_start_receive_data(HTTPContext
*c
);
258 static int http_receive_data(HTTPContext
*c
);
261 static int rtsp_parse_request(HTTPContext
*c
);
262 static void rtsp_cmd_describe(HTTPContext
*c
, const char *url
);
263 static void rtsp_cmd_options(HTTPContext
*c
, const char *url
);
264 static void rtsp_cmd_setup(HTTPContext
*c
, const char *url
, RTSPHeader
*h
);
265 static void rtsp_cmd_play(HTTPContext
*c
, const char *url
, RTSPHeader
*h
);
266 static void rtsp_cmd_pause(HTTPContext
*c
, const char *url
, RTSPHeader
*h
);
267 static void rtsp_cmd_teardown(HTTPContext
*c
, const char *url
, RTSPHeader
*h
);
270 static int prepare_sdp_description(FFStream
*stream
, uint8_t **pbuffer
,
271 struct in_addr my_ip
);
274 static HTTPContext
*rtp_new_connection(struct sockaddr_in
*from_addr
,
275 FFStream
*stream
, const char *session_id
,
276 enum RTSPProtocol rtp_protocol
);
277 static int rtp_new_av_stream(HTTPContext
*c
,
278 int stream_index
, struct sockaddr_in
*dest_addr
,
279 HTTPContext
*rtsp_c
);
281 static const char *my_program_name
;
282 static const char *my_program_dir
;
284 static int ffserver_debug
;
285 static int ffserver_daemon
;
286 static int no_launch
;
287 static int need_to_start_children
;
289 static int nb_max_connections
;
290 static int nb_connections
;
292 static int max_bandwidth
;
293 static int current_bandwidth
;
295 static int64_t cur_time
; // Making this global saves on passing it around everywhere
297 static AVRandomState random_state
;
299 static FILE *logfile
= NULL
;
301 static void __attribute__ ((format (printf
, 1, 2))) http_log(const char *fmt
, ...)
307 vfprintf(logfile
, fmt
, ap
);
313 static char *ctime1(char *buf2
)
321 p
= buf2
+ strlen(p
) - 1;
327 static void log_connection(HTTPContext
*c
)
334 http_log("%s - - [%s] \"%s %s %s\" %d %"PRId64
"\n",
335 inet_ntoa(c
->from_addr
.sin_addr
),
336 ctime1(buf2
), c
->method
, c
->url
,
337 c
->protocol
, (c
->http_error ? c
->http_error
: 200), c
->data_count
);
340 static void update_datarate(DataRateData
*drd
, int64_t count
)
342 if (!drd
->time1
&& !drd
->count1
) {
343 drd
->time1
= drd
->time2
= cur_time
;
344 drd
->count1
= drd
->count2
= count
;
345 } else if (cur_time
- drd
->time2
> 5000) {
346 drd
->time1
= drd
->time2
;
347 drd
->count1
= drd
->count2
;
348 drd
->time2
= cur_time
;
353 /* In bytes per second */
354 static int compute_datarate(DataRateData
*drd
, int64_t count
)
356 if (cur_time
== drd
->time1
)
359 return ((count
- drd
->count1
) * 1000) / (cur_time
- drd
->time1
);
363 static void start_children(FFStream
*feed
)
368 for (; feed
; feed
= feed
->next
) {
369 if (feed
->child_argv
&& !feed
->pid
) {
370 feed
->pid_start
= time(0);
375 fprintf(stderr
, "Unable to create children\n");
384 for (i
= 3; i
< 256; i
++)
387 if (!ffserver_debug
) {
388 i
= open("/dev/null", O_RDWR
);
397 av_strlcpy(pathname
, my_program_name
, sizeof(pathname
));
399 slash
= strrchr(pathname
, '/');
404 strcpy(slash
, "ffmpeg");
406 /* This is needed to make relative pathnames work */
407 chdir(my_program_dir
);
409 signal(SIGPIPE
, SIG_DFL
);
411 execvp(pathname
, feed
->child_argv
);
419 /* open a listening socket */
420 static int socket_open_listen(struct sockaddr_in
*my_addr
)
424 server_fd
= socket(AF_INET
,SOCK_STREAM
,0);
431 setsockopt(server_fd
, SOL_SOCKET
, SO_REUSEADDR
, &tmp
, sizeof(tmp
));
433 if (bind (server_fd
, (struct sockaddr
*) my_addr
, sizeof (*my_addr
)) < 0) {
435 snprintf(bindmsg
, sizeof(bindmsg
), "bind(port %d)", ntohs(my_addr
->sin_port
));
437 closesocket(server_fd
);
441 if (listen (server_fd
, 5) < 0) {
443 closesocket(server_fd
);
446 ff_socket_nonblock(server_fd
, 1);
451 /* start all multicast streams */
452 static void start_multicast(void)
457 struct sockaddr_in dest_addr
;
458 int default_port
, stream_index
;
461 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
462 if (stream
->is_multicast
) {
463 /* open the RTP connection */
464 snprintf(session_id
, sizeof(session_id
), "%08x%08x",
465 av_random(&random_state
), av_random(&random_state
));
467 /* choose a port if none given */
468 if (stream
->multicast_port
== 0) {
469 stream
->multicast_port
= default_port
;
473 dest_addr
.sin_family
= AF_INET
;
474 dest_addr
.sin_addr
= stream
->multicast_ip
;
475 dest_addr
.sin_port
= htons(stream
->multicast_port
);
477 rtp_c
= rtp_new_connection(&dest_addr
, stream
, session_id
,
478 RTSP_PROTOCOL_RTP_UDP_MULTICAST
);
482 if (open_input_stream(rtp_c
, "") < 0) {
483 fprintf(stderr
, "Could not open input stream for stream '%s'\n",
488 /* open each RTP stream */
489 for(stream_index
= 0; stream_index
< stream
->nb_streams
;
491 dest_addr
.sin_port
= htons(stream
->multicast_port
+
493 if (rtp_new_av_stream(rtp_c
, stream_index
, &dest_addr
, NULL
) < 0) {
494 fprintf(stderr
, "Could not open output stream '%s/streamid=%d'\n",
495 stream
->filename
, stream_index
);
500 /* change state to send data */
501 rtp_c
->state
= HTTPSTATE_SEND_DATA
;
506 /* main loop of the http server */
507 static int http_server(void)
509 int server_fd
, ret
, rtsp_server_fd
, delay
, delay1
;
510 struct pollfd poll_table
[HTTP_MAX_CONNECTIONS
+ 2], *poll_entry
;
511 HTTPContext
*c
, *c_next
;
513 server_fd
= socket_open_listen(&my_http_addr
);
517 rtsp_server_fd
= socket_open_listen(&my_rtsp_addr
);
518 if (rtsp_server_fd
< 0)
521 http_log("ffserver started.\n");
523 start_children(first_feed
);
525 first_http_ctx
= NULL
;
531 poll_entry
= poll_table
;
532 poll_entry
->fd
= server_fd
;
533 poll_entry
->events
= POLLIN
;
536 poll_entry
->fd
= rtsp_server_fd
;
537 poll_entry
->events
= POLLIN
;
540 /* wait for events on each HTTP handle */
547 case HTTPSTATE_SEND_HEADER
:
548 case RTSPSTATE_SEND_REPLY
:
549 case RTSPSTATE_SEND_PACKET
:
550 c
->poll_entry
= poll_entry
;
552 poll_entry
->events
= POLLOUT
;
555 case HTTPSTATE_SEND_DATA_HEADER
:
556 case HTTPSTATE_SEND_DATA
:
557 case HTTPSTATE_SEND_DATA_TRAILER
:
558 if (!c
->is_packetized
) {
559 /* for TCP, we output as much as we can (may need to put a limit) */
560 c
->poll_entry
= poll_entry
;
562 poll_entry
->events
= POLLOUT
;
565 /* when ffserver is doing the timing, we work by
566 looking at which packet need to be sent every
568 delay1
= 10; /* one tick wait XXX: 10 ms assumed */
573 case HTTPSTATE_WAIT_REQUEST
:
574 case HTTPSTATE_RECEIVE_DATA
:
575 case HTTPSTATE_WAIT_FEED
:
576 case RTSPSTATE_WAIT_REQUEST
:
577 /* need to catch errors */
578 c
->poll_entry
= poll_entry
;
580 poll_entry
->events
= POLLIN
;/* Maybe this will work */
584 c
->poll_entry
= NULL
;
590 /* wait for an event on one connection. We poll at least every
591 second to handle timeouts */
593 ret
= poll(poll_table
, poll_entry
- poll_table
, delay
);
594 if (ret
< 0 && ff_neterrno() != FF_NETERROR(EAGAIN
) &&
595 ff_neterrno() != FF_NETERROR(EINTR
))
599 cur_time
= av_gettime() / 1000;
601 if (need_to_start_children
) {
602 need_to_start_children
= 0;
603 start_children(first_feed
);
606 /* now handle the events */
607 for(c
= first_http_ctx
; c
!= NULL
; c
= c_next
) {
609 if (handle_connection(c
) < 0) {
610 /* close and free the connection */
616 poll_entry
= poll_table
;
617 /* new HTTP connection request ? */
618 if (poll_entry
->revents
& POLLIN
)
619 new_connection(server_fd
, 0);
621 /* new RTSP connection request ? */
622 if (poll_entry
->revents
& POLLIN
)
623 new_connection(rtsp_server_fd
, 1);
627 /* start waiting for a new HTTP/RTSP request */
628 static void start_wait_request(HTTPContext
*c
, int is_rtsp
)
630 c
->buffer_ptr
= c
->buffer
;
631 c
->buffer_end
= c
->buffer
+ c
->buffer_size
- 1; /* leave room for '\0' */
634 c
->timeout
= cur_time
+ RTSP_REQUEST_TIMEOUT
;
635 c
->state
= RTSPSTATE_WAIT_REQUEST
;
637 c
->timeout
= cur_time
+ HTTP_REQUEST_TIMEOUT
;
638 c
->state
= HTTPSTATE_WAIT_REQUEST
;
642 static void new_connection(int server_fd
, int is_rtsp
)
644 struct sockaddr_in from_addr
;
646 HTTPContext
*c
= NULL
;
648 len
= sizeof(from_addr
);
649 fd
= accept(server_fd
, (struct sockaddr
*)&from_addr
,
653 ff_socket_nonblock(fd
, 1);
655 /* XXX: should output a warning page when coming
656 close to the connection limit */
657 if (nb_connections
>= nb_max_connections
)
660 /* add a new connection */
661 c
= av_mallocz(sizeof(HTTPContext
));
666 c
->poll_entry
= NULL
;
667 c
->from_addr
= from_addr
;
668 c
->buffer_size
= IOBUFFER_INIT_SIZE
;
669 c
->buffer
= av_malloc(c
->buffer_size
);
673 c
->next
= first_http_ctx
;
677 start_wait_request(c
, is_rtsp
);
689 static void close_connection(HTTPContext
*c
)
691 HTTPContext
**cp
, *c1
;
693 AVFormatContext
*ctx
;
697 /* remove connection from list */
698 cp
= &first_http_ctx
;
699 while ((*cp
) != NULL
) {
707 /* remove references, if any (XXX: do it faster) */
708 for(c1
= first_http_ctx
; c1
!= NULL
; c1
= c1
->next
) {
713 /* remove connection associated resources */
717 /* close each frame parser */
718 for(i
=0;i
<c
->fmt_in
->nb_streams
;i
++) {
719 st
= c
->fmt_in
->streams
[i
];
720 if (st
->codec
->codec
)
721 avcodec_close(st
->codec
);
723 av_close_input_file(c
->fmt_in
);
726 /* free RTP output streams if any */
729 nb_streams
= c
->stream
->nb_streams
;
731 for(i
=0;i
<nb_streams
;i
++) {
734 av_write_trailer(ctx
);
737 h
= c
->rtp_handles
[i
];
744 if (!c
->last_packet_sent
) {
747 if (url_open_dyn_buf(&ctx
->pb
) >= 0) {
748 av_write_trailer(ctx
);
749 url_close_dyn_buf(&ctx
->pb
, &c
->pb_buffer
);
754 for(i
=0; i
<ctx
->nb_streams
; i
++)
755 av_free(ctx
->streams
[i
]);
757 if (c
->stream
&& !c
->post
&& c
->stream
->stream_type
== STREAM_TYPE_LIVE
)
758 current_bandwidth
-= c
->stream
->bandwidth
;
760 /* signal that there is no feed if we are the feeder socket */
761 if (c
->state
== HTTPSTATE_RECEIVE_DATA
&& c
->stream
) {
762 c
->stream
->feed_opened
= 0;
766 av_freep(&c
->pb_buffer
);
767 av_freep(&c
->packet_buffer
);
773 static int handle_connection(HTTPContext
*c
)
778 case HTTPSTATE_WAIT_REQUEST
:
779 case RTSPSTATE_WAIT_REQUEST
:
781 if ((c
->timeout
- cur_time
) < 0)
783 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
))
786 /* no need to read if no events */
787 if (!(c
->poll_entry
->revents
& POLLIN
))
791 len
= recv(c
->fd
, c
->buffer_ptr
, 1, 0);
793 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
794 ff_neterrno() != FF_NETERROR(EINTR
))
796 } else if (len
== 0) {
799 /* search for end of request. */
801 c
->buffer_ptr
+= len
;
803 if ((ptr
>= c
->buffer
+ 2 && !memcmp(ptr
-2, "\n\n", 2)) ||
804 (ptr
>= c
->buffer
+ 4 && !memcmp(ptr
-4, "\r\n\r\n", 4))) {
805 /* request found : parse it and reply */
806 if (c
->state
== HTTPSTATE_WAIT_REQUEST
) {
807 ret
= http_parse_request(c
);
809 ret
= rtsp_parse_request(c
);
813 } else if (ptr
>= c
->buffer_end
) {
814 /* request too long: cannot do anything */
816 } else goto read_loop
;
820 case HTTPSTATE_SEND_HEADER
:
821 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
))
824 /* no need to write if no events */
825 if (!(c
->poll_entry
->revents
& POLLOUT
))
827 len
= send(c
->fd
, c
->buffer_ptr
, c
->buffer_end
- c
->buffer_ptr
, 0);
829 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
830 ff_neterrno() != FF_NETERROR(EINTR
)) {
831 /* error : close connection */
832 av_freep(&c
->pb_buffer
);
836 c
->buffer_ptr
+= len
;
838 c
->stream
->bytes_served
+= len
;
839 c
->data_count
+= len
;
840 if (c
->buffer_ptr
>= c
->buffer_end
) {
841 av_freep(&c
->pb_buffer
);
845 /* all the buffer was sent : synchronize to the incoming stream */
846 c
->state
= HTTPSTATE_SEND_DATA_HEADER
;
847 c
->buffer_ptr
= c
->buffer_end
= c
->buffer
;
852 case HTTPSTATE_SEND_DATA
:
853 case HTTPSTATE_SEND_DATA_HEADER
:
854 case HTTPSTATE_SEND_DATA_TRAILER
:
855 /* for packetized output, we consider we can always write (the
856 input streams sets the speed). It may be better to verify
857 that we do not rely too much on the kernel queues */
858 if (!c
->is_packetized
) {
859 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
))
862 /* no need to read if no events */
863 if (!(c
->poll_entry
->revents
& POLLOUT
))
866 if (http_send_data(c
) < 0)
868 /* close connection if trailer sent */
869 if (c
->state
== HTTPSTATE_SEND_DATA_TRAILER
)
872 case HTTPSTATE_RECEIVE_DATA
:
873 /* no need to read if no events */
874 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
))
876 if (!(c
->poll_entry
->revents
& POLLIN
))
878 if (http_receive_data(c
) < 0)
881 case HTTPSTATE_WAIT_FEED
:
882 /* no need to read if no events */
883 if (c
->poll_entry
->revents
& (POLLIN
| POLLERR
| POLLHUP
))
886 /* nothing to do, we'll be waken up by incoming feed packets */
889 case RTSPSTATE_SEND_REPLY
:
890 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
)) {
891 av_freep(&c
->pb_buffer
);
894 /* no need to write if no events */
895 if (!(c
->poll_entry
->revents
& POLLOUT
))
897 len
= send(c
->fd
, c
->buffer_ptr
, c
->buffer_end
- c
->buffer_ptr
, 0);
899 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
900 ff_neterrno() != FF_NETERROR(EINTR
)) {
901 /* error : close connection */
902 av_freep(&c
->pb_buffer
);
906 c
->buffer_ptr
+= len
;
907 c
->data_count
+= len
;
908 if (c
->buffer_ptr
>= c
->buffer_end
) {
909 /* all the buffer was sent : wait for a new request */
910 av_freep(&c
->pb_buffer
);
911 start_wait_request(c
, 1);
915 case RTSPSTATE_SEND_PACKET
:
916 if (c
->poll_entry
->revents
& (POLLERR
| POLLHUP
)) {
917 av_freep(&c
->packet_buffer
);
920 /* no need to write if no events */
921 if (!(c
->poll_entry
->revents
& POLLOUT
))
923 len
= send(c
->fd
, c
->packet_buffer_ptr
,
924 c
->packet_buffer_end
- c
->packet_buffer_ptr
, 0);
926 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
927 ff_neterrno() != FF_NETERROR(EINTR
)) {
928 /* error : close connection */
929 av_freep(&c
->packet_buffer
);
933 c
->packet_buffer_ptr
+= len
;
934 if (c
->packet_buffer_ptr
>= c
->packet_buffer_end
) {
935 /* all the buffer was sent : wait for a new request */
936 av_freep(&c
->packet_buffer
);
937 c
->state
= RTSPSTATE_WAIT_REQUEST
;
941 case HTTPSTATE_READY
:
950 static int extract_rates(char *rates
, int ratelen
, const char *request
)
954 for (p
= request
; *p
&& *p
!= '\r' && *p
!= '\n'; ) {
955 if (strncasecmp(p
, "Pragma:", 7) == 0) {
956 const char *q
= p
+ 7;
958 while (*q
&& *q
!= '\n' && isspace(*q
))
961 if (strncasecmp(q
, "stream-switch-entry=", 20) == 0) {
967 memset(rates
, 0xff, ratelen
);
970 while (*q
&& *q
!= '\n' && *q
!= ':')
973 if (sscanf(q
, ":%d:%d", &stream_no
, &rate_no
) != 2)
977 if (stream_no
< ratelen
&& stream_no
>= 0)
978 rates
[stream_no
] = rate_no
;
980 while (*q
&& *q
!= '\n' && !isspace(*q
))
997 static int find_stream_in_feed(FFStream
*feed
, AVCodecContext
*codec
, int bit_rate
)
1000 int best_bitrate
= 100000000;
1003 for (i
= 0; i
< feed
->nb_streams
; i
++) {
1004 AVCodecContext
*feed_codec
= feed
->streams
[i
]->codec
;
1006 if (feed_codec
->codec_id
!= codec
->codec_id
||
1007 feed_codec
->sample_rate
!= codec
->sample_rate
||
1008 feed_codec
->width
!= codec
->width
||
1009 feed_codec
->height
!= codec
->height
)
1012 /* Potential stream */
1014 /* We want the fastest stream less than bit_rate, or the slowest
1015 * faster than bit_rate
1018 if (feed_codec
->bit_rate
<= bit_rate
) {
1019 if (best_bitrate
> bit_rate
|| feed_codec
->bit_rate
> best_bitrate
) {
1020 best_bitrate
= feed_codec
->bit_rate
;
1024 if (feed_codec
->bit_rate
< best_bitrate
) {
1025 best_bitrate
= feed_codec
->bit_rate
;
1034 static int modify_current_stream(HTTPContext
*c
, char *rates
)
1037 FFStream
*req
= c
->stream
;
1038 int action_required
= 0;
1040 /* Not much we can do for a feed */
1044 for (i
= 0; i
< req
->nb_streams
; i
++) {
1045 AVCodecContext
*codec
= req
->streams
[i
]->codec
;
1049 c
->switch_feed_streams
[i
] = req
->feed_streams
[i
];
1052 c
->switch_feed_streams
[i
] = find_stream_in_feed(req
->feed
, codec
, codec
->bit_rate
/ 2);
1055 /* Wants off or slow */
1056 c
->switch_feed_streams
[i
] = find_stream_in_feed(req
->feed
, codec
, codec
->bit_rate
/ 4);
1058 /* This doesn't work well when it turns off the only stream! */
1059 c
->switch_feed_streams
[i
] = -2;
1060 c
->feed_streams
[i
] = -2;
1065 if (c
->switch_feed_streams
[i
] >= 0 && c
->switch_feed_streams
[i
] != c
->feed_streams
[i
])
1066 action_required
= 1;
1069 return action_required
;
1073 static void do_switch_stream(HTTPContext
*c
, int i
)
1075 if (c
->switch_feed_streams
[i
] >= 0) {
1077 c
->feed_streams
[i
] = c
->switch_feed_streams
[i
];
1080 /* Now update the stream */
1082 c
->switch_feed_streams
[i
] = -1;
1085 /* XXX: factorize in utils.c ? */
1086 /* XXX: take care with different space meaning */
1087 static void skip_spaces(const char **pp
)
1091 while (*p
== ' ' || *p
== '\t')
1096 static void get_word(char *buf
, int buf_size
, const char **pp
)
1104 while (!isspace(*p
) && *p
!= '\0') {
1105 if ((q
- buf
) < buf_size
- 1)
1114 static int validate_acl(FFStream
*stream
, HTTPContext
*c
)
1116 enum IPAddressAction last_action
= IP_DENY
;
1118 struct in_addr
*src
= &c
->from_addr
.sin_addr
;
1119 unsigned long src_addr
= src
->s_addr
;
1121 for (acl
= stream
->acl
; acl
; acl
= acl
->next
) {
1122 if (src_addr
>= acl
->first
.s_addr
&& src_addr
<= acl
->last
.s_addr
)
1123 return (acl
->action
== IP_ALLOW
) ?
1 : 0;
1124 last_action
= acl
->action
;
1127 /* Nothing matched, so return not the last action */
1128 return (last_action
== IP_DENY
) ?
1 : 0;
1131 /* compute the real filename of a file by matching it without its
1132 extensions to all the stream filenames */
1133 static void compute_real_filename(char *filename
, int max_size
)
1140 /* compute filename by matching without the file extensions */
1141 av_strlcpy(file1
, filename
, sizeof(file1
));
1142 p
= strrchr(file1
, '.');
1145 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
1146 av_strlcpy(file2
, stream
->filename
, sizeof(file2
));
1147 p
= strrchr(file2
, '.');
1150 if (!strcmp(file1
, file2
)) {
1151 av_strlcpy(filename
, stream
->filename
, max_size
);
1166 /* parse http request and prepare header */
1167 static int http_parse_request(HTTPContext
*c
)
1170 enum RedirType redir_type
;
1172 char info
[1024], filename
[1024];
1176 const char *mime_type
;
1180 char *useragent
= 0;
1183 get_word(cmd
, sizeof(cmd
), (const char **)&p
);
1184 av_strlcpy(c
->method
, cmd
, sizeof(c
->method
));
1186 if (!strcmp(cmd
, "GET"))
1188 else if (!strcmp(cmd
, "POST"))
1193 get_word(url
, sizeof(url
), (const char **)&p
);
1194 av_strlcpy(c
->url
, url
, sizeof(c
->url
));
1196 get_word(protocol
, sizeof(protocol
), (const char **)&p
);
1197 if (strcmp(protocol
, "HTTP/1.0") && strcmp(protocol
, "HTTP/1.1"))
1200 av_strlcpy(c
->protocol
, protocol
, sizeof(c
->protocol
));
1203 http_log("New connection: %s %s\n", cmd
, url
);
1205 /* find the filename and the optional info string in the request */
1206 p
= strchr(url
, '?');
1208 av_strlcpy(info
, p
, sizeof(info
));
1213 av_strlcpy(filename
, url
+ ((*url
== '/') ?
1 : 0), sizeof(filename
)-1);
1215 for (p
= c
->buffer
; *p
&& *p
!= '\r' && *p
!= '\n'; ) {
1216 if (strncasecmp(p
, "User-Agent:", 11) == 0) {
1218 if (*useragent
&& *useragent
!= '\n' && isspace(*useragent
))
1222 p
= strchr(p
, '\n');
1229 redir_type
= REDIR_NONE
;
1230 if (match_ext(filename
, "asx")) {
1231 redir_type
= REDIR_ASX
;
1232 filename
[strlen(filename
)-1] = 'f';
1233 } else if (match_ext(filename
, "asf") &&
1234 (!useragent
|| strncasecmp(useragent
, "NSPlayer", 8) != 0)) {
1235 /* if this isn't WMP or lookalike, return the redirector file */
1236 redir_type
= REDIR_ASF
;
1237 } else if (match_ext(filename
, "rpm,ram")) {
1238 redir_type
= REDIR_RAM
;
1239 strcpy(filename
+ strlen(filename
)-2, "m");
1240 } else if (match_ext(filename
, "rtsp")) {
1241 redir_type
= REDIR_RTSP
;
1242 compute_real_filename(filename
, sizeof(filename
) - 1);
1243 } else if (match_ext(filename
, "sdp")) {
1244 redir_type
= REDIR_SDP
;
1245 compute_real_filename(filename
, sizeof(filename
) - 1);
1248 // "redirect" / request to index.html
1249 if (!strlen(filename
))
1250 av_strlcpy(filename
, "index.html", sizeof(filename
) - 1);
1252 stream
= first_stream
;
1253 while (stream
!= NULL
) {
1254 if (!strcmp(stream
->filename
, filename
) && validate_acl(stream
, c
))
1256 stream
= stream
->next
;
1258 if (stream
== NULL
) {
1259 snprintf(msg
, sizeof(msg
), "File '%s' not found", url
);
1264 memcpy(c
->feed_streams
, stream
->feed_streams
, sizeof(c
->feed_streams
));
1265 memset(c
->switch_feed_streams
, -1, sizeof(c
->switch_feed_streams
));
1267 if (stream
->stream_type
== STREAM_TYPE_REDIRECT
) {
1268 c
->http_error
= 301;
1270 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 301 Moved\r\n");
1271 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Location: %s\r\n", stream
->feed_filename
);
1272 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-type: text/html\r\n");
1273 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1274 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<html><head><title>Moved</title></head><body>\r\n");
1275 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "You should be <a href=\"%s\">redirected</a>.\r\n", stream
->feed_filename
);
1276 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "</body></html>\r\n");
1278 /* prepare output buffer */
1279 c
->buffer_ptr
= c
->buffer
;
1281 c
->state
= HTTPSTATE_SEND_HEADER
;
1285 /* If this is WMP, get the rate information */
1286 if (extract_rates(ratebuf
, sizeof(ratebuf
), c
->buffer
)) {
1287 if (modify_current_stream(c
, ratebuf
)) {
1288 for (i
= 0; i
< sizeof(c
->feed_streams
) / sizeof(c
->feed_streams
[0]); i
++) {
1289 if (c
->switch_feed_streams
[i
] >= 0)
1290 do_switch_stream(c
, i
);
1295 /* If already streaming this feed, do not let start another feeder. */
1296 if (stream
->feed_opened
) {
1297 snprintf(msg
, sizeof(msg
), "This feed is already being received.");
1301 if (c
->post
== 0 && stream
->stream_type
== STREAM_TYPE_LIVE
)
1302 current_bandwidth
+= stream
->bandwidth
;
1304 if (c
->post
== 0 && max_bandwidth
< current_bandwidth
) {
1305 c
->http_error
= 200;
1307 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 200 Server too busy\r\n");
1308 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-type: text/html\r\n");
1309 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1310 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<html><head><title>Too busy</title></head><body>\r\n");
1311 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<p>The server is too busy to serve your request at this time.</p>\r\n");
1312 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<p>The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec.</p>\r\n",
1313 current_bandwidth
, max_bandwidth
);
1314 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "</body></html>\r\n");
1316 /* prepare output buffer */
1317 c
->buffer_ptr
= c
->buffer
;
1319 c
->state
= HTTPSTATE_SEND_HEADER
;
1323 if (redir_type
!= REDIR_NONE
) {
1326 for (p
= c
->buffer
; *p
&& *p
!= '\r' && *p
!= '\n'; ) {
1327 if (strncasecmp(p
, "Host:", 5) == 0) {
1331 p
= strchr(p
, '\n');
1342 while (isspace(*hostinfo
))
1345 eoh
= strchr(hostinfo
, '\n');
1347 if (eoh
[-1] == '\r')
1350 if (eoh
- hostinfo
< sizeof(hostbuf
) - 1) {
1351 memcpy(hostbuf
, hostinfo
, eoh
- hostinfo
);
1352 hostbuf
[eoh
- hostinfo
] = 0;
1354 c
->http_error
= 200;
1356 switch(redir_type
) {
1358 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 200 ASX Follows\r\n");
1359 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-type: video/x-ms-asf\r\n");
1360 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1361 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<ASX Version=\"3\">\r\n");
1362 //q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<!-- Autogenerated by ffserver -->\r\n");
1363 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
1364 hostbuf
, filename
, info
);
1365 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "</ASX>\r\n");
1368 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 200 RAM Follows\r\n");
1369 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-type: audio/x-pn-realaudio\r\n");
1370 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1371 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "# Autogenerated by ffserver\r\n");
1372 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "http://%s/%s%s\r\n",
1373 hostbuf
, filename
, info
);
1376 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 200 ASF Redirect follows\r\n");
1377 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-type: video/x-ms-asf\r\n");
1378 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1379 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "[Reference]\r\n");
1380 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Ref1=http://%s/%s%s\r\n",
1381 hostbuf
, filename
, info
);
1385 char hostname
[256], *p
;
1386 /* extract only hostname */
1387 av_strlcpy(hostname
, hostbuf
, sizeof(hostname
));
1388 p
= strrchr(hostname
, ':');
1391 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 200 RTSP Redirect follows\r\n");
1392 /* XXX: incorrect mime type ? */
1393 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-type: application/x-rtsp\r\n");
1394 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1395 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "rtsp://%s:%d/%s\r\n",
1396 hostname
, ntohs(my_rtsp_addr
.sin_port
),
1403 int sdp_data_size
, len
;
1404 struct sockaddr_in my_addr
;
1406 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 200 OK\r\n");
1407 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-type: application/sdp\r\n");
1408 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1410 len
= sizeof(my_addr
);
1411 getsockname(c
->fd
, (struct sockaddr
*)&my_addr
, &len
);
1413 /* XXX: should use a dynamic buffer */
1414 sdp_data_size
= prepare_sdp_description(stream
,
1417 if (sdp_data_size
> 0) {
1418 memcpy(q
, sdp_data
, sdp_data_size
);
1430 /* prepare output buffer */
1431 c
->buffer_ptr
= c
->buffer
;
1433 c
->state
= HTTPSTATE_SEND_HEADER
;
1439 snprintf(msg
, sizeof(msg
), "ASX/RAM file not handled");
1443 stream
->conns_served
++;
1445 /* XXX: add there authenticate and IP match */
1448 /* if post, it means a feed is being sent */
1449 if (!stream
->is_feed
) {
1450 /* However it might be a status report from WMP! Lets log the data
1451 * as it might come in handy one day
1456 for (p
= c
->buffer
; *p
&& *p
!= '\r' && *p
!= '\n'; ) {
1457 if (strncasecmp(p
, "Pragma: log-line=", 17) == 0) {
1461 if (strncasecmp(p
, "Pragma: client-id=", 18) == 0)
1462 client_id
= strtol(p
+ 18, 0, 10);
1463 p
= strchr(p
, '\n');
1471 char *eol
= strchr(logline
, '\n');
1476 if (eol
[-1] == '\r')
1478 http_log("%.*s\n", (int) (eol
- logline
), logline
);
1479 c
->suppress_log
= 1;
1484 http_log("\nGot request:\n%s\n", c
->buffer
);
1487 if (client_id
&& extract_rates(ratebuf
, sizeof(ratebuf
), c
->buffer
)) {
1490 /* Now we have to find the client_id */
1491 for (wmpc
= first_http_ctx
; wmpc
; wmpc
= wmpc
->next
) {
1492 if (wmpc
->wmp_client_id
== client_id
)
1496 if (wmpc
&& modify_current_stream(wmpc
, ratebuf
))
1497 wmpc
->switch_pending
= 1;
1500 snprintf(msg
, sizeof(msg
), "POST command not handled");
1504 if (http_start_receive_data(c
) < 0) {
1505 snprintf(msg
, sizeof(msg
), "could not open feed");
1509 c
->state
= HTTPSTATE_RECEIVE_DATA
;
1514 if (strcmp(stream
->filename
+ strlen(stream
->filename
) - 4, ".asf") == 0)
1515 http_log("\nGot request:\n%s\n", c
->buffer
);
1518 if (c
->stream
->stream_type
== STREAM_TYPE_STATUS
)
1521 /* open input stream */
1522 if (open_input_stream(c
, info
) < 0) {
1523 snprintf(msg
, sizeof(msg
), "Input stream corresponding to '%s' not found", url
);
1527 /* prepare http header */
1529 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 200 OK\r\n");
1530 mime_type
= c
->stream
->fmt
->mime_type
;
1532 mime_type
= "application/x-octet-stream";
1533 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Pragma: no-cache\r\n");
1535 /* for asf, we need extra headers */
1536 if (!strcmp(c
->stream
->fmt
->name
,"asf_stream")) {
1537 /* Need to allocate a client id */
1539 c
->wmp_client_id
= av_random(&random_state
) & 0x7fffffff;
1541 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
);
1543 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-Type: %s\r\n", mime_type
);
1544 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1546 /* prepare output buffer */
1548 c
->buffer_ptr
= c
->buffer
;
1550 c
->state
= HTTPSTATE_SEND_HEADER
;
1553 c
->http_error
= 404;
1555 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "HTTP/1.0 404 Not Found\r\n");
1556 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "Content-type: %s\r\n", "text/html");
1557 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "\r\n");
1558 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<HTML>\n");
1559 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1560 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "<BODY>%s</BODY>\n", msg
);
1561 q
+= snprintf(q
, q
- (char *) c
->buffer
+ c
->buffer_size
, "</HTML>\n");
1563 /* prepare output buffer */
1564 c
->buffer_ptr
= c
->buffer
;
1566 c
->state
= HTTPSTATE_SEND_HEADER
;
1570 c
->http_error
= 200; /* horrible : we use this value to avoid
1571 going to the send data state */
1572 c
->state
= HTTPSTATE_SEND_HEADER
;
1576 static void fmt_bytecount(ByteIOContext
*pb
, int64_t count
)
1578 static const char *suffix
= " kMGTP";
1581 for (s
= suffix
; count
>= 100000 && s
[1]; count
/= 1000, s
++);
1583 url_fprintf(pb
, "%"PRId64
"%c", count
, *s
);
1586 static void compute_stats(HTTPContext
*c
)
1593 ByteIOContext pb1
, *pb
= &pb1
;
1595 if (url_open_dyn_buf(pb
) < 0) {
1596 /* XXX: return an error ? */
1597 c
->buffer_ptr
= c
->buffer
;
1598 c
->buffer_end
= c
->buffer
;
1602 url_fprintf(pb
, "HTTP/1.0 200 OK\r\n");
1603 url_fprintf(pb
, "Content-type: %s\r\n", "text/html");
1604 url_fprintf(pb
, "Pragma: no-cache\r\n");
1605 url_fprintf(pb
, "\r\n");
1607 url_fprintf(pb
, "<HEAD><TITLE>FFServer Status</TITLE>\n");
1608 if (c
->stream
->feed_filename
)
1609 url_fprintf(pb
, "<link rel=\"shortcut icon\" href=\"%s\">\n", c
->stream
->feed_filename
);
1610 url_fprintf(pb
, "</HEAD>\n<BODY>");
1611 url_fprintf(pb
, "<H1>FFServer Status</H1>\n");
1613 url_fprintf(pb
, "<H2>Available Streams</H2>\n");
1614 url_fprintf(pb
, "<TABLE cellspacing=0 cellpadding=4>\n");
1615 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");
1616 stream
= first_stream
;
1617 while (stream
!= NULL
) {
1618 char sfilename
[1024];
1621 if (stream
->feed
!= stream
) {
1622 av_strlcpy(sfilename
, stream
->filename
, sizeof(sfilename
) - 10);
1623 eosf
= sfilename
+ strlen(sfilename
);
1624 if (eosf
- sfilename
>= 4) {
1625 if (strcmp(eosf
- 4, ".asf") == 0)
1626 strcpy(eosf
- 4, ".asx");
1627 else if (strcmp(eosf
- 3, ".rm") == 0)
1628 strcpy(eosf
- 3, ".ram");
1629 else if (stream
->fmt
== &rtp_muxer
) {
1630 /* generate a sample RTSP director if
1631 unicast. Generate an SDP redirector if
1633 eosf
= strrchr(sfilename
, '.');
1635 eosf
= sfilename
+ strlen(sfilename
);
1636 if (stream
->is_multicast
)
1637 strcpy(eosf
, ".sdp");
1639 strcpy(eosf
, ".rtsp");
1643 url_fprintf(pb
, "<TR><TD><A HREF=\"/%s\">%s</A> ",
1644 sfilename
, stream
->filename
);
1645 url_fprintf(pb
, "<td align=right> %d <td align=right> ",
1646 stream
->conns_served
);
1647 fmt_bytecount(pb
, stream
->bytes_served
);
1648 switch(stream
->stream_type
) {
1649 case STREAM_TYPE_LIVE
:
1651 int audio_bit_rate
= 0;
1652 int video_bit_rate
= 0;
1653 const char *audio_codec_name
= "";
1654 const char *video_codec_name
= "";
1655 const char *audio_codec_name_extra
= "";
1656 const char *video_codec_name_extra
= "";
1658 for(i
=0;i
<stream
->nb_streams
;i
++) {
1659 AVStream
*st
= stream
->streams
[i
];
1660 AVCodec
*codec
= avcodec_find_encoder(st
->codec
->codec_id
);
1661 switch(st
->codec
->codec_type
) {
1662 case CODEC_TYPE_AUDIO
:
1663 audio_bit_rate
+= st
->codec
->bit_rate
;
1665 if (*audio_codec_name
)
1666 audio_codec_name_extra
= "...";
1667 audio_codec_name
= codec
->name
;
1670 case CODEC_TYPE_VIDEO
:
1671 video_bit_rate
+= st
->codec
->bit_rate
;
1673 if (*video_codec_name
)
1674 video_codec_name_extra
= "...";
1675 video_codec_name
= codec
->name
;
1678 case CODEC_TYPE_DATA
:
1679 video_bit_rate
+= st
->codec
->bit_rate
;
1685 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",
1688 video_bit_rate
/ 1000, video_codec_name
, video_codec_name_extra
,
1689 audio_bit_rate
/ 1000, audio_codec_name
, audio_codec_name_extra
);
1691 url_fprintf(pb
, "<TD>%s", stream
->feed
->filename
);
1693 url_fprintf(pb
, "<TD>%s", stream
->feed_filename
);
1694 url_fprintf(pb
, "\n");
1698 url_fprintf(pb
, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
1702 stream
= stream
->next
;
1704 url_fprintf(pb
, "</TABLE>\n");
1706 stream
= first_stream
;
1707 while (stream
!= NULL
) {
1708 if (stream
->feed
== stream
) {
1709 url_fprintf(pb
, "<h2>Feed %s</h2>", stream
->filename
);
1711 url_fprintf(pb
, "Running as pid %d.\n", stream
->pid
);
1713 #if defined(linux) && !defined(CONFIG_NOCUTILS)
1718 /* This is somewhat linux specific I guess */
1719 snprintf(ps_cmd
, sizeof(ps_cmd
),
1720 "ps -o \"%%cpu,cputime\" --no-headers %d",
1723 pid_stat
= popen(ps_cmd
, "r");
1728 if (fscanf(pid_stat
, "%10s %64s", cpuperc
,
1730 url_fprintf(pb
, "Currently using %s%% of the cpu. Total time used %s.\n",
1738 url_fprintf(pb
, "<p>");
1740 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");
1742 for (i
= 0; i
< stream
->nb_streams
; i
++) {
1743 AVStream
*st
= stream
->streams
[i
];
1744 AVCodec
*codec
= avcodec_find_encoder(st
->codec
->codec_id
);
1745 const char *type
= "unknown";
1746 char parameters
[64];
1750 switch(st
->codec
->codec_type
) {
1751 case CODEC_TYPE_AUDIO
:
1753 snprintf(parameters
, sizeof(parameters
), "%d channel(s), %d Hz", st
->codec
->channels
, st
->codec
->sample_rate
);
1755 case CODEC_TYPE_VIDEO
:
1757 snprintf(parameters
, sizeof(parameters
), "%dx%d, q=%d-%d, fps=%d", st
->codec
->width
, st
->codec
->height
,
1758 st
->codec
->qmin
, st
->codec
->qmax
, st
->codec
->time_base
.den
/ st
->codec
->time_base
.num
);
1763 url_fprintf(pb
, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1764 i
, type
, st
->codec
->bit_rate
/1000, codec ? codec
->name
: "", parameters
);
1766 url_fprintf(pb
, "</table>\n");
1769 stream
= stream
->next
;
1775 AVCodecContext
*enc
;
1779 stream
= first_feed
;
1780 while (stream
!= NULL
) {
1781 url_fprintf(pb
, "<H1>Feed '%s'</H1>\n", stream
->filename
);
1782 url_fprintf(pb
, "<TABLE>\n");
1783 url_fprintf(pb
, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
1784 for(i
=0;i
<stream
->nb_streams
;i
++) {
1785 AVStream
*st
= stream
->streams
[i
];
1786 FeedData
*fdata
= st
->priv_data
;
1789 avcodec_string(buf
, sizeof(buf
), enc
);
1790 avg
= fdata
->avg_frame_size
* (float)enc
->rate
* 8.0;
1791 if (enc
->codec
->type
== CODEC_TYPE_AUDIO
&& enc
->frame_size
> 0)
1792 avg
/= enc
->frame_size
;
1793 url_fprintf(pb
, "<TR><TD>%s <TD> %d <TD> %"PRId64
" <TD> %0.1f\n",
1794 buf
, enc
->frame_number
, fdata
->data_count
, avg
/ 1000.0);
1796 url_fprintf(pb
, "</TABLE>\n");
1797 stream
= stream
->next_feed
;
1802 /* connection status */
1803 url_fprintf(pb
, "<H2>Connection Status</H2>\n");
1805 url_fprintf(pb
, "Number of connections: %d / %d<BR>\n",
1806 nb_connections
, nb_max_connections
);
1808 url_fprintf(pb
, "Bandwidth in use: %dk / %dk<BR>\n",
1809 current_bandwidth
, max_bandwidth
);
1811 url_fprintf(pb
, "<TABLE>\n");
1812 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");
1813 c1
= first_http_ctx
;
1815 while (c1
!= NULL
) {
1821 for (j
= 0; j
< c1
->stream
->nb_streams
; j
++) {
1822 if (!c1
->stream
->feed
)
1823 bitrate
+= c1
->stream
->streams
[j
]->codec
->bit_rate
;
1824 else if (c1
->feed_streams
[j
] >= 0)
1825 bitrate
+= c1
->stream
->feed
->streams
[c1
->feed_streams
[j
]]->codec
->bit_rate
;
1830 p
= inet_ntoa(c1
->from_addr
.sin_addr
);
1831 url_fprintf(pb
, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1833 c1
->stream ? c1
->stream
->filename
: "",
1834 c1
->state
== HTTPSTATE_RECEIVE_DATA ?
"(input)" : "",
1837 http_state
[c1
->state
]);
1838 fmt_bytecount(pb
, bitrate
);
1839 url_fprintf(pb
, "<td align=right>");
1840 fmt_bytecount(pb
, compute_datarate(&c1
->datarate
, c1
->data_count
) * 8);
1841 url_fprintf(pb
, "<td align=right>");
1842 fmt_bytecount(pb
, c1
->data_count
);
1843 url_fprintf(pb
, "\n");
1846 url_fprintf(pb
, "</TABLE>\n");
1851 url_fprintf(pb
, "<HR size=1 noshade>Generated at %s", p
);
1852 url_fprintf(pb
, "</BODY>\n</HTML>\n");
1854 len
= url_close_dyn_buf(pb
, &c
->pb_buffer
);
1855 c
->buffer_ptr
= c
->pb_buffer
;
1856 c
->buffer_end
= c
->pb_buffer
+ len
;
1859 /* check if the parser needs to be opened for stream i */
1860 static void open_parser(AVFormatContext
*s
, int i
)
1862 AVStream
*st
= s
->streams
[i
];
1865 if (!st
->codec
->codec
) {
1866 codec
= avcodec_find_decoder(st
->codec
->codec_id
);
1867 if (codec
&& (codec
->capabilities
& CODEC_CAP_PARSE_ONLY
)) {
1868 st
->codec
->parse_only
= 1;
1869 if (avcodec_open(st
->codec
, codec
) < 0)
1870 st
->codec
->parse_only
= 0;
1875 static int open_input_stream(HTTPContext
*c
, const char *info
)
1878 char input_filename
[1024];
1883 /* find file name */
1884 if (c
->stream
->feed
) {
1885 strcpy(input_filename
, c
->stream
->feed
->feed_filename
);
1886 buf_size
= FFM_PACKET_SIZE
;
1887 /* compute position (absolute time) */
1888 if (find_info_tag(buf
, sizeof(buf
), "date", info
))
1889 stream_pos
= parse_date(buf
, 0);
1890 else if (find_info_tag(buf
, sizeof(buf
), "buffer", info
)) {
1891 int prebuffer
= strtol(buf
, 0, 10);
1892 stream_pos
= av_gettime() - prebuffer
* (int64_t)1000000;
1894 stream_pos
= av_gettime() - c
->stream
->prebuffer
* (int64_t)1000;
1896 strcpy(input_filename
, c
->stream
->feed_filename
);
1898 /* compute position (relative time) */
1899 if (find_info_tag(buf
, sizeof(buf
), "date", info
))
1900 stream_pos
= parse_date(buf
, 1);
1904 if (input_filename
[0] == '\0')
1908 { time_t when
= stream_pos
/ 1000000;
1909 http_log("Stream pos = %"PRId64
", time=%s", stream_pos
, ctime(&when
));
1914 if (av_open_input_file(&s
, input_filename
, c
->stream
->ifmt
,
1915 buf_size
, c
->stream
->ap_in
) < 0) {
1916 http_log("%s not found", input_filename
);
1920 av_find_stream_info(c
->fmt_in
);
1922 /* open each parser */
1923 for(i
=0;i
<s
->nb_streams
;i
++)
1926 /* choose stream as clock source (we favorize video stream if
1927 present) for packet sending */
1928 c
->pts_stream_index
= 0;
1929 for(i
=0;i
<c
->stream
->nb_streams
;i
++) {
1930 if (c
->pts_stream_index
== 0 &&
1931 c
->stream
->streams
[i
]->codec
->codec_type
== CODEC_TYPE_VIDEO
) {
1932 c
->pts_stream_index
= i
;
1937 if (c
->fmt_in
->iformat
->read_seek
)
1938 c
->fmt_in
->iformat
->read_seek(c
->fmt_in
, 0, stream_pos
, 0);
1940 /* set the start time (needed for maxtime and RTP packet timing) */
1941 c
->start_time
= cur_time
;
1942 c
->first_pts
= AV_NOPTS_VALUE
;
1946 /* return the server clock (in us) */
1947 static int64_t get_server_clock(HTTPContext
*c
)
1949 /* compute current pts value from system time */
1950 return (cur_time
- c
->start_time
) * 1000;
1953 /* return the estimated time at which the current packet must be sent
1955 static int64_t get_packet_send_clock(HTTPContext
*c
)
1957 int bytes_left
, bytes_sent
, frame_bytes
;
1959 frame_bytes
= c
->cur_frame_bytes
;
1960 if (frame_bytes
<= 0)
1963 bytes_left
= c
->buffer_end
- c
->buffer_ptr
;
1964 bytes_sent
= frame_bytes
- bytes_left
;
1965 return c
->cur_pts
+ (c
->cur_frame_duration
* bytes_sent
) / frame_bytes
;
1970 static int http_prepare_data(HTTPContext
*c
)
1973 AVFormatContext
*ctx
;
1975 av_freep(&c
->pb_buffer
);
1977 case HTTPSTATE_SEND_DATA_HEADER
:
1978 memset(&c
->fmt_ctx
, 0, sizeof(c
->fmt_ctx
));
1979 av_strlcpy(c
->fmt_ctx
.author
, c
->stream
->author
,
1980 sizeof(c
->fmt_ctx
.author
));
1981 av_strlcpy(c
->fmt_ctx
.comment
, c
->stream
->comment
,
1982 sizeof(c
->fmt_ctx
.comment
));
1983 av_strlcpy(c
->fmt_ctx
.copyright
, c
->stream
->copyright
,
1984 sizeof(c
->fmt_ctx
.copyright
));
1985 av_strlcpy(c
->fmt_ctx
.title
, c
->stream
->title
,
1986 sizeof(c
->fmt_ctx
.title
));
1988 /* open output stream by using specified codecs */
1989 c
->fmt_ctx
.oformat
= c
->stream
->fmt
;
1990 c
->fmt_ctx
.nb_streams
= c
->stream
->nb_streams
;
1991 for(i
=0;i
<c
->fmt_ctx
.nb_streams
;i
++) {
1994 st
= av_mallocz(sizeof(AVStream
));
1995 st
->codec
= avcodec_alloc_context();
1996 c
->fmt_ctx
.streams
[i
] = st
;
1997 /* if file or feed, then just take streams from FFStream struct */
1998 if (!c
->stream
->feed
||
1999 c
->stream
->feed
== c
->stream
)
2000 src
= c
->stream
->streams
[i
];
2002 src
= c
->stream
->feed
->streams
[c
->stream
->feed_streams
[i
]];
2006 st
->codec
->frame_number
= 0; /* XXX: should be done in
2007 AVStream, not in codec */
2008 /* I'm pretty sure that this is not correct...
2009 * However, without it, we crash
2011 st
->codec
->coded_frame
= &dummy_frame
;
2013 c
->got_key_frame
= 0;
2015 /* prepare header and save header data in a stream */
2016 if (url_open_dyn_buf(&c
->fmt_ctx
.pb
) < 0) {
2017 /* XXX: potential leak */
2020 c
->fmt_ctx
.pb
.is_streamed
= 1;
2022 av_set_parameters(&c
->fmt_ctx
, NULL
);
2023 if (av_write_header(&c
->fmt_ctx
) < 0)
2026 len
= url_close_dyn_buf(&c
->fmt_ctx
.pb
, &c
->pb_buffer
);
2027 c
->buffer_ptr
= c
->pb_buffer
;
2028 c
->buffer_end
= c
->pb_buffer
+ len
;
2030 c
->state
= HTTPSTATE_SEND_DATA
;
2031 c
->last_packet_sent
= 0;
2033 case HTTPSTATE_SEND_DATA
:
2034 /* find a new packet */
2038 /* read a packet from the input stream */
2039 if (c
->stream
->feed
)
2040 ffm_set_write_index(c
->fmt_in
,
2041 c
->stream
->feed
->feed_write_index
,
2042 c
->stream
->feed
->feed_size
);
2044 if (c
->stream
->max_time
&&
2045 c
->stream
->max_time
+ c
->start_time
- cur_time
< 0)
2046 /* We have timed out */
2047 c
->state
= HTTPSTATE_SEND_DATA_TRAILER
;
2050 if (av_read_frame(c
->fmt_in
, &pkt
) < 0) {
2051 if (c
->stream
->feed
&& c
->stream
->feed
->feed_opened
) {
2052 /* if coming from feed, it means we reached the end of the
2053 ffm file, so must wait for more data */
2054 c
->state
= HTTPSTATE_WAIT_FEED
;
2055 return 1; /* state changed */
2057 if (c
->stream
->loop
) {
2058 av_close_input_file(c
->fmt_in
);
2060 if (open_input_stream(c
, "") < 0)
2065 /* must send trailer now because eof or error */
2066 c
->state
= HTTPSTATE_SEND_DATA_TRAILER
;
2070 /* update first pts if needed */
2071 if (c
->first_pts
== AV_NOPTS_VALUE
) {
2072 c
->first_pts
= av_rescale_q(pkt
.dts
, c
->fmt_in
->streams
[pkt
.stream_index
]->time_base
, AV_TIME_BASE_Q
);
2073 c
->start_time
= cur_time
;
2075 /* send it to the appropriate stream */
2076 if (c
->stream
->feed
) {
2077 /* if coming from a feed, select the right stream */
2078 if (c
->switch_pending
) {
2079 c
->switch_pending
= 0;
2080 for(i
=0;i
<c
->stream
->nb_streams
;i
++) {
2081 if (c
->switch_feed_streams
[i
] == pkt
.stream_index
)
2082 if (pkt
.flags
& PKT_FLAG_KEY
)
2083 do_switch_stream(c
, i
);
2084 if (c
->switch_feed_streams
[i
] >= 0)
2085 c
->switch_pending
= 1;
2088 for(i
=0;i
<c
->stream
->nb_streams
;i
++) {
2089 if (c
->feed_streams
[i
] == pkt
.stream_index
) {
2090 pkt
.stream_index
= i
;
2091 if (pkt
.flags
& PKT_FLAG_KEY
)
2092 c
->got_key_frame
|= 1 << i
;
2093 /* See if we have all the key frames, then
2094 * we start to send. This logic is not quite
2095 * right, but it works for the case of a
2096 * single video stream with one or more
2097 * audio streams (for which every frame is
2098 * typically a key frame).
2100 if (!c
->stream
->send_on_key
||
2101 ((c
->got_key_frame
+ 1) >> c
->stream
->nb_streams
))
2106 AVCodecContext
*codec
;
2109 /* specific handling for RTP: we use several
2110 output stream (one for each RTP
2111 connection). XXX: need more abstract handling */
2112 if (c
->is_packetized
) {
2114 /* compute send time and duration */
2115 st
= c
->fmt_in
->streams
[pkt
.stream_index
];
2116 c
->cur_pts
= av_rescale_q(pkt
.dts
, st
->time_base
, AV_TIME_BASE_Q
);
2117 if (st
->start_time
!= AV_NOPTS_VALUE
)
2118 c
->cur_pts
-= av_rescale_q(st
->start_time
, st
->time_base
, AV_TIME_BASE_Q
);
2119 c
->cur_frame_duration
= av_rescale_q(pkt
.duration
, st
->time_base
, AV_TIME_BASE_Q
);
2121 printf("index=%d pts=%0.3f duration=%0.6f\n",
2123 (double)c
->cur_pts
/
2125 (double)c
->cur_frame_duration
/
2128 /* find RTP context */
2129 c
->packet_stream_index
= pkt
.stream_index
;
2130 ctx
= c
->rtp_ctx
[c
->packet_stream_index
];
2132 av_free_packet(&pkt
);
2135 codec
= ctx
->streams
[0]->codec
;
2136 /* only one stream per RTP connection */
2137 pkt
.stream_index
= 0;
2141 codec
= ctx
->streams
[pkt
.stream_index
]->codec
;
2144 codec
->coded_frame
->key_frame
= ((pkt
.flags
& PKT_FLAG_KEY
) != 0);
2145 if (c
->is_packetized
) {
2146 int max_packet_size
;
2147 if (c
->rtp_protocol
== RTSP_PROTOCOL_RTP_TCP
)
2148 max_packet_size
= RTSP_TCP_MAX_PACKET_SIZE
;
2150 max_packet_size
= url_get_max_packet_size(c
->rtp_handles
[c
->packet_stream_index
]);
2151 ret
= url_open_dyn_packet_buf(&ctx
->pb
, max_packet_size
);
2153 ret
= url_open_dyn_buf(&ctx
->pb
);
2156 /* XXX: potential leak */
2159 if (pkt
.dts
!= AV_NOPTS_VALUE
)
2160 pkt
.dts
= av_rescale_q(pkt
.dts
,
2161 c
->fmt_in
->streams
[pkt
.stream_index
]->time_base
,
2162 ctx
->streams
[pkt
.stream_index
]->time_base
);
2163 if (pkt
.pts
!= AV_NOPTS_VALUE
)
2164 pkt
.pts
= av_rescale_q(pkt
.pts
,
2165 c
->fmt_in
->streams
[pkt
.stream_index
]->time_base
,
2166 ctx
->streams
[pkt
.stream_index
]->time_base
);
2167 if (av_write_frame(ctx
, &pkt
))
2168 c
->state
= HTTPSTATE_SEND_DATA_TRAILER
;
2170 len
= url_close_dyn_buf(&ctx
->pb
, &c
->pb_buffer
);
2171 c
->cur_frame_bytes
= len
;
2172 c
->buffer_ptr
= c
->pb_buffer
;
2173 c
->buffer_end
= c
->pb_buffer
+ len
;
2175 codec
->frame_number
++;
2179 av_free_packet(&pkt
);
2185 case HTTPSTATE_SEND_DATA_TRAILER
:
2186 /* last packet test ? */
2187 if (c
->last_packet_sent
|| c
->is_packetized
)
2190 /* prepare header */
2191 if (url_open_dyn_buf(&ctx
->pb
) < 0) {
2192 /* XXX: potential leak */
2195 av_write_trailer(ctx
);
2196 len
= url_close_dyn_buf(&ctx
->pb
, &c
->pb_buffer
);
2197 c
->buffer_ptr
= c
->pb_buffer
;
2198 c
->buffer_end
= c
->pb_buffer
+ len
;
2200 c
->last_packet_sent
= 1;
2206 /* should convert the format at the same time */
2207 /* send data starting at c->buffer_ptr to the output connection
2208 (either UDP or TCP connection) */
2209 static int http_send_data(HTTPContext
*c
)
2214 if (c
->buffer_ptr
>= c
->buffer_end
) {
2215 ret
= http_prepare_data(c
);
2219 /* state change requested */
2222 if (c
->is_packetized
) {
2223 /* RTP data output */
2224 len
= c
->buffer_end
- c
->buffer_ptr
;
2226 /* fail safe - should never happen */
2228 c
->buffer_ptr
= c
->buffer_end
;
2231 len
= (c
->buffer_ptr
[0] << 24) |
2232 (c
->buffer_ptr
[1] << 16) |
2233 (c
->buffer_ptr
[2] << 8) |
2235 if (len
> (c
->buffer_end
- c
->buffer_ptr
))
2237 if ((get_packet_send_clock(c
) - get_server_clock(c
)) > 0) {
2238 /* nothing to send yet: we can wait */
2242 c
->data_count
+= len
;
2243 update_datarate(&c
->datarate
, c
->data_count
);
2245 c
->stream
->bytes_served
+= len
;
2247 if (c
->rtp_protocol
== RTSP_PROTOCOL_RTP_TCP
) {
2248 /* RTP packets are sent inside the RTSP TCP connection */
2249 ByteIOContext pb1
, *pb
= &pb1
;
2250 int interleaved_index
, size
;
2252 HTTPContext
*rtsp_c
;
2255 /* if no RTSP connection left, error */
2258 /* if already sending something, then wait. */
2259 if (rtsp_c
->state
!= RTSPSTATE_WAIT_REQUEST
)
2261 if (url_open_dyn_buf(pb
) < 0)
2263 interleaved_index
= c
->packet_stream_index
* 2;
2264 /* RTCP packets are sent at odd indexes */
2265 if (c
->buffer_ptr
[1] == 200)
2266 interleaved_index
++;
2267 /* write RTSP TCP header */
2269 header
[1] = interleaved_index
;
2270 header
[2] = len
>> 8;
2272 put_buffer(pb
, header
, 4);
2273 /* write RTP packet data */
2275 put_buffer(pb
, c
->buffer_ptr
, len
);
2276 size
= url_close_dyn_buf(pb
, &c
->packet_buffer
);
2277 /* prepare asynchronous TCP sending */
2278 rtsp_c
->packet_buffer_ptr
= c
->packet_buffer
;
2279 rtsp_c
->packet_buffer_end
= c
->packet_buffer
+ size
;
2280 c
->buffer_ptr
+= len
;
2282 /* send everything we can NOW */
2283 len
= send(rtsp_c
->fd
, rtsp_c
->packet_buffer_ptr
,
2284 rtsp_c
->packet_buffer_end
- rtsp_c
->packet_buffer_ptr
, 0);
2286 rtsp_c
->packet_buffer_ptr
+= len
;
2287 if (rtsp_c
->packet_buffer_ptr
< rtsp_c
->packet_buffer_end
) {
2288 /* if we could not send all the data, we will
2289 send it later, so a new state is needed to
2290 "lock" the RTSP TCP connection */
2291 rtsp_c
->state
= RTSPSTATE_SEND_PACKET
;
2294 /* all data has been sent */
2295 av_freep(&c
->packet_buffer
);
2297 /* send RTP packet directly in UDP */
2299 url_write(c
->rtp_handles
[c
->packet_stream_index
],
2300 c
->buffer_ptr
, len
);
2301 c
->buffer_ptr
+= len
;
2302 /* here we continue as we can send several packets per 10 ms slot */
2305 /* TCP data output */
2306 len
= send(c
->fd
, c
->buffer_ptr
, c
->buffer_end
- c
->buffer_ptr
, 0);
2308 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
2309 ff_neterrno() != FF_NETERROR(EINTR
))
2310 /* error : close connection */
2315 c
->buffer_ptr
+= len
;
2317 c
->data_count
+= len
;
2318 update_datarate(&c
->datarate
, c
->data_count
);
2320 c
->stream
->bytes_served
+= len
;
2328 static int http_start_receive_data(HTTPContext
*c
)
2332 if (c
->stream
->feed_opened
)
2335 /* Don't permit writing to this one */
2336 if (c
->stream
->readonly
)
2340 fd
= open(c
->stream
->feed_filename
, O_RDWR
);
2345 c
->stream
->feed_write_index
= ffm_read_write_index(fd
);
2346 c
->stream
->feed_size
= lseek(fd
, 0, SEEK_END
);
2347 lseek(fd
, 0, SEEK_SET
);
2349 /* init buffer input */
2350 c
->buffer_ptr
= c
->buffer
;
2351 c
->buffer_end
= c
->buffer
+ FFM_PACKET_SIZE
;
2352 c
->stream
->feed_opened
= 1;
2356 static int http_receive_data(HTTPContext
*c
)
2360 if (c
->buffer_end
> c
->buffer_ptr
) {
2363 len
= recv(c
->fd
, c
->buffer_ptr
, c
->buffer_end
- c
->buffer_ptr
, 0);
2365 if (ff_neterrno() != FF_NETERROR(EAGAIN
) &&
2366 ff_neterrno() != FF_NETERROR(EINTR
))
2367 /* error : close connection */
2369 } else if (len
== 0)
2370 /* end of connection : close it */
2373 c
->buffer_ptr
+= len
;
2374 c
->data_count
+= len
;
2375 update_datarate(&c
->datarate
, c
->data_count
);
2379 if (c
->buffer_ptr
- c
->buffer
>= 2 && c
->data_count
> FFM_PACKET_SIZE
) {
2380 if (c
->buffer
[0] != 'f' ||
2381 c
->buffer
[1] != 'm') {
2382 http_log("Feed stream has become desynchronized -- disconnecting\n");
2387 if (c
->buffer_ptr
>= c
->buffer_end
) {
2388 FFStream
*feed
= c
->stream
;
2389 /* a packet has been received : write it in the store, except
2391 if (c
->data_count
> FFM_PACKET_SIZE
) {
2393 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2394 /* XXX: use llseek or url_seek */
2395 lseek(c
->feed_fd
, feed
->feed_write_index
, SEEK_SET
);
2396 write(c
->feed_fd
, c
->buffer
, FFM_PACKET_SIZE
);
2398 feed
->feed_write_index
+= FFM_PACKET_SIZE
;
2399 /* update file size */
2400 if (feed
->feed_write_index
> c
->stream
->feed_size
)
2401 feed
->feed_size
= feed
->feed_write_index
;
2403 /* handle wrap around if max file size reached */
2404 if (c
->stream
->feed_max_size
&& feed
->feed_write_index
>= c
->stream
->feed_max_size
)
2405 feed
->feed_write_index
= FFM_PACKET_SIZE
;
2408 ffm_write_write_index(c
->feed_fd
, feed
->feed_write_index
);
2410 /* wake up any waiting connections */
2411 for(c1
= first_http_ctx
; c1
!= NULL
; c1
= c1
->next
) {
2412 if (c1
->state
== HTTPSTATE_WAIT_FEED
&&
2413 c1
->stream
->feed
== c
->stream
->feed
)
2414 c1
->state
= HTTPSTATE_SEND_DATA
;
2417 /* We have a header in our hands that contains useful data */
2419 AVInputFormat
*fmt_in
;
2420 ByteIOContext
*pb
= &s
.pb
;
2423 memset(&s
, 0, sizeof(s
));
2425 url_open_buf(pb
, c
->buffer
, c
->buffer_end
- c
->buffer
, URL_RDONLY
);
2426 pb
->buf_end
= c
->buffer_end
; /* ?? */
2427 pb
->is_streamed
= 1;
2429 /* use feed output format name to find corresponding input format */
2430 fmt_in
= av_find_input_format(feed
->fmt
->name
);
2434 if (fmt_in
->priv_data_size
> 0) {
2435 s
.priv_data
= av_mallocz(fmt_in
->priv_data_size
);
2441 if (fmt_in
->read_header(&s
, 0) < 0) {
2442 av_freep(&s
.priv_data
);
2446 /* Now we have the actual streams */
2447 if (s
.nb_streams
!= feed
->nb_streams
) {
2448 av_freep(&s
.priv_data
);
2451 for (i
= 0; i
< s
.nb_streams
; i
++)
2452 memcpy(feed
->streams
[i
]->codec
,
2453 s
.streams
[i
]->codec
, sizeof(AVCodecContext
));
2454 av_freep(&s
.priv_data
);
2456 c
->buffer_ptr
= c
->buffer
;
2461 c
->stream
->feed_opened
= 0;
2466 /********************************************************************/
2469 static void rtsp_reply_header(HTTPContext
*c
, enum RTSPStatusCode error_number
)
2476 switch(error_number
) {
2477 case RTSP_STATUS_OK
:
2480 case RTSP_STATUS_METHOD
:
2481 str
= "Method Not Allowed";
2483 case RTSP_STATUS_BANDWIDTH
:
2484 str
= "Not Enough Bandwidth";
2486 case RTSP_STATUS_SESSION
:
2487 str
= "Session Not Found";
2489 case RTSP_STATUS_STATE
:
2490 str
= "Method Not Valid in This State";
2492 case RTSP_STATUS_AGGREGATE
:
2493 str
= "Aggregate operation not allowed";
2495 case RTSP_STATUS_ONLY_AGGREGATE
:
2496 str
= "Only aggregate operation allowed";
2498 case RTSP_STATUS_TRANSPORT
:
2499 str
= "Unsupported transport";
2501 case RTSP_STATUS_INTERNAL
:
2502 str
= "Internal Server Error";
2504 case RTSP_STATUS_SERVICE
:
2505 str
= "Service Unavailable";
2507 case RTSP_STATUS_VERSION
:
2508 str
= "RTSP Version not supported";
2511 str
= "Unknown Error";
2515 url_fprintf(c
->pb
, "RTSP/1.0 %d %s\r\n", error_number
, str
);
2516 url_fprintf(c
->pb
, "CSeq: %d\r\n", c
->seq
);
2518 /* output GMT time */
2522 p
= buf2
+ strlen(p
) - 1;
2525 url_fprintf(c
->pb
, "Date: %s GMT\r\n", buf2
);
2528 static void rtsp_reply_error(HTTPContext
*c
, enum RTSPStatusCode error_number
)
2530 rtsp_reply_header(c
, error_number
);
2531 url_fprintf(c
->pb
, "\r\n");
2534 static int rtsp_parse_request(HTTPContext
*c
)
2536 const char *p
, *p1
, *p2
;
2543 RTSPHeader header1
, *header
= &header1
;
2545 c
->buffer_ptr
[0] = '\0';
2548 get_word(cmd
, sizeof(cmd
), &p
);
2549 get_word(url
, sizeof(url
), &p
);
2550 get_word(protocol
, sizeof(protocol
), &p
);
2552 av_strlcpy(c
->method
, cmd
, sizeof(c
->method
));
2553 av_strlcpy(c
->url
, url
, sizeof(c
->url
));
2554 av_strlcpy(c
->protocol
, protocol
, sizeof(c
->protocol
));
2557 if (url_open_dyn_buf(c
->pb
) < 0) {
2558 /* XXX: cannot do more */
2559 c
->pb
= NULL
; /* safety */
2563 /* check version name */
2564 if (strcmp(protocol
, "RTSP/1.0") != 0) {
2565 rtsp_reply_error(c
, RTSP_STATUS_VERSION
);
2569 /* parse each header line */
2570 memset(header
, 0, sizeof(RTSPHeader
));
2571 /* skip to next line */
2572 while (*p
!= '\n' && *p
!= '\0')
2576 while (*p
!= '\0') {
2577 p1
= strchr(p
, '\n');
2581 if (p2
> p
&& p2
[-1] == '\r')
2583 /* skip empty line */
2587 if (len
> sizeof(line
) - 1)
2588 len
= sizeof(line
) - 1;
2589 memcpy(line
, p
, len
);
2591 rtsp_parse_line(header
, line
);
2595 /* handle sequence number */
2596 c
->seq
= header
->seq
;
2598 if (!strcmp(cmd
, "DESCRIBE"))
2599 rtsp_cmd_describe(c
, url
);
2600 else if (!strcmp(cmd
, "OPTIONS"))
2601 rtsp_cmd_options(c
, url
);
2602 else if (!strcmp(cmd
, "SETUP"))
2603 rtsp_cmd_setup(c
, url
, header
);
2604 else if (!strcmp(cmd
, "PLAY"))
2605 rtsp_cmd_play(c
, url
, header
);
2606 else if (!strcmp(cmd
, "PAUSE"))
2607 rtsp_cmd_pause(c
, url
, header
);
2608 else if (!strcmp(cmd
, "TEARDOWN"))
2609 rtsp_cmd_teardown(c
, url
, header
);
2611 rtsp_reply_error(c
, RTSP_STATUS_METHOD
);
2614 len
= url_close_dyn_buf(c
->pb
, &c
->pb_buffer
);
2615 c
->pb
= NULL
; /* safety */
2617 /* XXX: cannot do more */
2620 c
->buffer_ptr
= c
->pb_buffer
;
2621 c
->buffer_end
= c
->pb_buffer
+ len
;
2622 c
->state
= RTSPSTATE_SEND_REPLY
;
2626 static int prepare_sdp_description(FFStream
*stream
, uint8_t **pbuffer
,
2627 struct in_addr my_ip
)
2629 AVFormatContext
*avc
;
2630 AVStream avs
[MAX_STREAMS
];
2633 avc
= av_alloc_format_context();
2637 if (stream
->title
[0] != 0) {
2638 av_strlcpy(avc
->title
, stream
->title
, sizeof(avc
->title
));
2640 av_strlcpy(avc
->title
, "No Title", sizeof(avc
->title
));
2642 avc
->nb_streams
= stream
->nb_streams
;
2643 if (stream
->is_multicast
) {
2644 snprintf(avc
->filename
, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2645 inet_ntoa(stream
->multicast_ip
),
2646 stream
->multicast_port
, stream
->multicast_ttl
);
2649 for(i
= 0; i
< stream
->nb_streams
; i
++) {
2650 avc
->streams
[i
] = &avs
[i
];
2651 avc
->streams
[i
]->codec
= stream
->streams
[i
]->codec
;
2653 *pbuffer
= av_mallocz(2048);
2654 avf_sdp_create(&avc
, 1, *pbuffer
, 2048);
2657 return strlen(*pbuffer
);
2660 static void rtsp_cmd_options(HTTPContext
*c
, const char *url
)
2662 // rtsp_reply_header(c, RTSP_STATUS_OK);
2663 url_fprintf(c
->pb
, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK
, "OK");
2664 url_fprintf(c
->pb
, "CSeq: %d\r\n", c
->seq
);
2665 url_fprintf(c
->pb
, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2666 url_fprintf(c
->pb
, "\r\n");
2669 static void rtsp_cmd_describe(HTTPContext
*c
, const char *url
)
2675 int content_length
, len
;
2676 struct sockaddr_in my_addr
;
2678 /* find which url is asked */
2679 url_split(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, path1
, sizeof(path1
), url
);
2684 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
2685 if (!stream
->is_feed
&& stream
->fmt
== &rtp_muxer
&&
2686 !strcmp(path
, stream
->filename
)) {
2690 /* no stream found */
2691 rtsp_reply_error(c
, RTSP_STATUS_SERVICE
); /* XXX: right error ? */
2695 /* prepare the media description in sdp format */
2697 /* get the host IP */
2698 len
= sizeof(my_addr
);
2699 getsockname(c
->fd
, (struct sockaddr
*)&my_addr
, &len
);
2700 content_length
= prepare_sdp_description(stream
, &content
, my_addr
.sin_addr
);
2701 if (content_length
< 0) {
2702 rtsp_reply_error(c
, RTSP_STATUS_INTERNAL
);
2705 rtsp_reply_header(c
, RTSP_STATUS_OK
);
2706 url_fprintf(c
->pb
, "Content-Type: application/sdp\r\n");
2707 url_fprintf(c
->pb
, "Content-Length: %d\r\n", content_length
);
2708 url_fprintf(c
->pb
, "\r\n");
2709 put_buffer(c
->pb
, content
, content_length
);
2712 static HTTPContext
*find_rtp_session(const char *session_id
)
2716 if (session_id
[0] == '\0')
2719 for(c
= first_http_ctx
; c
!= NULL
; c
= c
->next
) {
2720 if (!strcmp(c
->session_id
, session_id
))
2726 static RTSPTransportField
*find_transport(RTSPHeader
*h
, enum RTSPProtocol protocol
)
2728 RTSPTransportField
*th
;
2731 for(i
=0;i
<h
->nb_transports
;i
++) {
2732 th
= &h
->transports
[i
];
2733 if (th
->protocol
== protocol
)
2739 static void rtsp_cmd_setup(HTTPContext
*c
, const char *url
,
2743 int stream_index
, port
;
2748 RTSPTransportField
*th
;
2749 struct sockaddr_in dest_addr
;
2750 RTSPActionServerSetup setup
;
2752 /* find which url is asked */
2753 url_split(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, path1
, sizeof(path1
), url
);
2758 /* now check each stream */
2759 for(stream
= first_stream
; stream
!= NULL
; stream
= stream
->next
) {
2760 if (!stream
->is_feed
&& stream
->fmt
== &rtp_muxer
) {
2761 /* accept aggregate filenames only if single stream */
2762 if (!strcmp(path
, stream
->filename
)) {
2763 if (stream
->nb_streams
!= 1) {
2764 rtsp_reply_error(c
, RTSP_STATUS_AGGREGATE
);
2771 for(stream_index
= 0; stream_index
< stream
->nb_streams
;
2773 snprintf(buf
, sizeof(buf
), "%s/streamid=%d",
2774 stream
->filename
, stream_index
);
2775 if (!strcmp(path
, buf
))
2780 /* no stream found */
2781 rtsp_reply_error(c
, RTSP_STATUS_SERVICE
); /* XXX: right error ? */
2785 /* generate session id if needed */
2786 if (h
->session_id
[0] == '\0')
2787 snprintf(h
->session_id
, sizeof(h
->session_id
), "%08x%08x",
2788 av_random(&random_state
), av_random(&random_state
));
2790 /* find rtp session, and create it if none found */
2791 rtp_c
= find_rtp_session(h
->session_id
);
2793 /* always prefer UDP */
2794 th
= find_transport(h
, RTSP_PROTOCOL_RTP_UDP
);
2796 th
= find_transport(h
, RTSP_PROTOCOL_RTP_TCP
);
2798 rtsp_reply_error(c
, RTSP_STATUS_TRANSPORT
);
2803 rtp_c
= rtp_new_connection(&c
->from_addr
, stream
, h
->session_id
,
2806 rtsp_reply_error(c
, RTSP_STATUS_BANDWIDTH
);
2810 /* open input stream */
2811 if (open_input_stream(rtp_c
, "") < 0) {
2812 rtsp_reply_error(c
, RTSP_STATUS_INTERNAL
);
2817 /* test if stream is OK (test needed because several SETUP needs
2818 to be done for a given file) */
2819 if (rtp_c
->stream
!= stream
) {
2820 rtsp_reply_error(c
, RTSP_STATUS_SERVICE
);
2824 /* test if stream is already set up */
2825 if (rtp_c
->rtp_ctx
[stream_index
]) {
2826 rtsp_reply_error(c
, RTSP_STATUS_STATE
);
2830 /* check transport */
2831 th
= find_transport(h
, rtp_c
->rtp_protocol
);
2832 if (!th
|| (th
->protocol
== RTSP_PROTOCOL_RTP_UDP
&&
2833 th
->client_port_min
<= 0)) {
2834 rtsp_reply_error(c
, RTSP_STATUS_TRANSPORT
);
2838 /* setup default options */
2839 setup
.transport_option
[0] = '\0';
2840 dest_addr
= rtp_c
->from_addr
;
2841 dest_addr
.sin_port
= htons(th
->client_port_min
);
2844 if (rtp_new_av_stream(rtp_c
, stream_index
, &dest_addr
, c
) < 0) {
2845 rtsp_reply_error(c
, RTSP_STATUS_TRANSPORT
);
2849 /* now everything is OK, so we can send the connection parameters */
2850 rtsp_reply_header(c
, RTSP_STATUS_OK
);
2852 url_fprintf(c
->pb
, "Session: %s\r\n", rtp_c
->session_id
);
2854 switch(rtp_c
->rtp_protocol
) {
2855 case RTSP_PROTOCOL_RTP_UDP
:
2856 port
= rtp_get_local_port(rtp_c
->rtp_handles
[stream_index
]);
2857 url_fprintf(c
->pb
, "Transport: RTP/AVP/UDP;unicast;"
2858 "client_port=%d-%d;server_port=%d-%d",
2859 th
->client_port_min
, th
->client_port_min
+ 1,
2862 case RTSP_PROTOCOL_RTP_TCP
:
2863 url_fprintf(c
->pb
, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2864 stream_index
* 2, stream_index
* 2 + 1);
2869 if (setup
.transport_option
[0] != '\0')
2870 url_fprintf(c
->pb
, ";%s", setup
.transport_option
);
2871 url_fprintf(c
->pb
, "\r\n");
2874 url_fprintf(c
->pb
, "\r\n");
2878 /* find an rtp connection by using the session ID. Check consistency
2880 static HTTPContext
*find_rtp_session_with_url(const char *url
,
2881 const char *session_id
)
2889 rtp_c
= find_rtp_session(session_id
);
2893 /* find which url is asked */
2894 url_split(NULL
, 0, NULL
, 0, NULL
, 0, NULL
, path1
, sizeof(path1
), url
);
2898 if(!strcmp(path
, rtp_c
->stream
->filename
)) return rtp_c
;
2899 for(s
=0; s
<rtp_c
->stream
->nb_streams
; ++s
) {
2900 snprintf(buf
, sizeof(buf
), "%s/streamid=%d",
2901 rtp_c
->stream
->filename
, s
);
2902 if(!strncmp(path
, buf
, sizeof(buf
))) {
2903 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2910 static void rtsp_cmd_play(HTTPContext
*c
, const char *url
, RTSPHeader
*h
)
2914 rtp_c
= find_rtp_session_with_url(url
, h
->session_id
);
2916 rtsp_reply_error(c
, RTSP_STATUS_SESSION
);
2920 if (rtp_c
->state
!= HTTPSTATE_SEND_DATA
&&
2921 rtp_c
->state
!= HTTPSTATE_WAIT_FEED
&&
2922 rtp_c
->state
!= HTTPSTATE_READY
) {
2923 rtsp_reply_error(c
, RTSP_STATUS_STATE
);
2928 /* XXX: seek in stream */
2929 if (h
->range_start
!= AV_NOPTS_VALUE
) {
2930 printf("range_start=%0.3f\n", (double)h
->range_start
/ AV_TIME_BASE
);
2931 av_seek_frame(rtp_c
->fmt_in
, -1, h
->range_start
);
2935 rtp_c
->state
= HTTPSTATE_SEND_DATA
;
2937 /* now everything is OK, so we can send the connection parameters */
2938 rtsp_reply_header(c
, RTSP_STATUS_OK
);
2940 url_fprintf(c
->pb
, "Session: %s\r\n", rtp_c
->session_id
);
2941 url_fprintf(c
->pb
, "\r\n");
2944 static void rtsp_cmd_pause(HTTPContext
*c
, const char *url
, RTSPHeader
*h
)
2948 rtp_c
= find_rtp_session_with_url(url
, h
->session_id
);
2950 rtsp_reply_error(c
, RTSP_STATUS_SESSION
);
2954 if (rtp_c
->state
!= HTTPSTATE_SEND_DATA
&&
2955 rtp_c
->state
!= HTTPSTATE_WAIT_FEED
) {
2956 rtsp_reply_error(c
, RTSP_STATUS_STATE
);
2960 rtp_c
->state
= HTTPSTATE_READY
;
2961 rtp_c
->first_pts
= AV_NOPTS_VALUE
;
2962 /* now everything is OK, so we can send the connection parameters */
2963 rtsp_reply_header(c
, RTSP_STATUS_OK
);
2965 url_fprintf(c
->pb
, "Session: %s\r\n", rtp_c
->session_id
);
2966 url_fprintf(c
->pb
, "\r\n");
2969 static void rtsp_cmd_teardown(HTTPContext
*c
, const char *url
, RTSPHeader
*h
)
2972 char session_id
[32];
2974 rtp_c
= find_rtp_session_with_url(url
, h
->session_id
);
2976 rtsp_reply_error(c
, RTSP_STATUS_SESSION
);
2980 av_strlcpy(session_id
, rtp_c
->session_id
, sizeof(session_id
));
2982 /* abort the session */
2983 close_connection(rtp_c
);
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", session_id
);
2989 url_fprintf(c
->pb
, "\r\n");
2993 /********************************************************************/
2996 static HTTPContext
*rtp_new_connection(struct sockaddr_in
*from_addr
,
2997 FFStream
*stream
, const char *session_id
,
2998 enum RTSPProtocol rtp_protocol
)
3000 HTTPContext
*c
= NULL
;
3001 const char *proto_str
;
3003 /* XXX: should output a warning page when coming
3004 close to the connection limit */
3005 if (nb_connections
>= nb_max_connections
)
3008 /* add a new connection */
3009 c
= av_mallocz(sizeof(HTTPContext
));
3014 c
->poll_entry
= NULL
;
3015 c
->from_addr
= *from_addr
;
3016 c
->buffer_size
= IOBUFFER_INIT_SIZE
;
3017 c
->buffer
= av_malloc(c
->buffer_size
);
3022 av_strlcpy(c
->session_id
, session_id
, sizeof(c
->session_id
));
3023 c
->state
= HTTPSTATE_READY
;
3024 c
->is_packetized
= 1;
3025 c
->rtp_protocol
= rtp_protocol
;
3027 /* protocol is shown in statistics */
3028 switch(c
->rtp_protocol
) {
3029 case RTSP_PROTOCOL_RTP_UDP_MULTICAST
:
3030 proto_str
= "MCAST";
3032 case RTSP_PROTOCOL_RTP_UDP
:
3035 case RTSP_PROTOCOL_RTP_TCP
:
3042 av_strlcpy(c
->protocol
, "RTP/", sizeof(c
->protocol
));
3043 av_strlcat(c
->protocol
, proto_str
, sizeof(c
->protocol
));
3045 current_bandwidth
+= stream
->bandwidth
;
3047 c
->next
= first_http_ctx
;
3059 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3060 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3062 static int rtp_new_av_stream(HTTPContext
*c
,
3063 int stream_index
, struct sockaddr_in
*dest_addr
,
3064 HTTPContext
*rtsp_c
)
3066 AVFormatContext
*ctx
;
3072 int max_packet_size
;
3074 /* now we can open the relevant output stream */
3075 ctx
= av_alloc_format_context();
3078 ctx
->oformat
= &rtp_muxer
;
3080 st
= av_mallocz(sizeof(AVStream
));
3083 st
->codec
= avcodec_alloc_context();
3084 ctx
->nb_streams
= 1;
3085 ctx
->streams
[0] = st
;
3087 if (!c
->stream
->feed
||
3088 c
->stream
->feed
== c
->stream
)
3089 memcpy(st
, c
->stream
->streams
[stream_index
], sizeof(AVStream
));
3092 c
->stream
->feed
->streams
[c
->stream
->feed_streams
[stream_index
]],
3094 st
->priv_data
= NULL
;
3096 /* build destination RTP address */
3097 ipaddr
= inet_ntoa(dest_addr
->sin_addr
);
3099 switch(c
->rtp_protocol
) {
3100 case RTSP_PROTOCOL_RTP_UDP
:
3101 case RTSP_PROTOCOL_RTP_UDP_MULTICAST
:
3104 /* XXX: also pass as parameter to function ? */
3105 if (c
->stream
->is_multicast
) {
3107 ttl
= c
->stream
->multicast_ttl
;
3110 snprintf(ctx
->filename
, sizeof(ctx
->filename
),
3111 "rtp://%s:%d?multicast=1&ttl=%d",
3112 ipaddr
, ntohs(dest_addr
->sin_port
), ttl
);
3114 snprintf(ctx
->filename
, sizeof(ctx
->filename
),
3115 "rtp://%s:%d", ipaddr
, ntohs(dest_addr
->sin_port
));
3118 if (url_open(&h
, ctx
->filename
, URL_WRONLY
) < 0)
3120 c
->rtp_handles
[stream_index
] = h
;
3121 max_packet_size
= url_get_max_packet_size(h
);
3123 case RTSP_PROTOCOL_RTP_TCP
:
3126 max_packet_size
= RTSP_TCP_MAX_PACKET_SIZE
;
3132 http_log("%s:%d - - [%s] \"PLAY %s/streamid=%d %s\"\n",
3133 ipaddr
, ntohs(dest_addr
->sin_port
),
3135 c
->stream
->filename
, stream_index
, c
->protocol
);
3137 /* normally, no packets should be output here, but the packet size may be checked */
3138 if (url_open_dyn_packet_buf(&ctx
->pb
, max_packet_size
) < 0) {
3139 /* XXX: close stream */
3142 av_set_parameters(ctx
, NULL
);
3143 if (av_write_header(ctx
) < 0) {
3150 url_close_dyn_buf(&ctx
->pb
, &dummy_buf
);
3153 c
->rtp_ctx
[stream_index
] = ctx
;
3157 /********************************************************************/
3158 /* ffserver initialization */
3160 static AVStream
*add_av_stream1(FFStream
*stream
, AVCodecContext
*codec
)
3164 fst
= av_mallocz(sizeof(AVStream
));
3167 fst
->codec
= avcodec_alloc_context();
3168 fst
->priv_data
= av_mallocz(sizeof(FeedData
));
3169 memcpy(fst
->codec
, codec
, sizeof(AVCodecContext
));
3170 fst
->codec
->coded_frame
= &dummy_frame
;
3171 fst
->index
= stream
->nb_streams
;
3172 av_set_pts_info(fst
, 33, 1, 90000);
3173 stream
->streams
[stream
->nb_streams
++] = fst
;
3177 /* return the stream number in the feed */
3178 static int add_av_stream(FFStream
*feed
, AVStream
*st
)
3181 AVCodecContext
*av
, *av1
;
3185 for(i
=0;i
<feed
->nb_streams
;i
++) {
3186 st
= feed
->streams
[i
];
3188 if (av1
->codec_id
== av
->codec_id
&&
3189 av1
->codec_type
== av
->codec_type
&&
3190 av1
->bit_rate
== av
->bit_rate
) {
3192 switch(av
->codec_type
) {
3193 case CODEC_TYPE_AUDIO
:
3194 if (av1
->channels
== av
->channels
&&
3195 av1
->sample_rate
== av
->sample_rate
)
3198 case CODEC_TYPE_VIDEO
:
3199 if (av1
->width
== av
->width
&&
3200 av1
->height
== av
->height
&&
3201 av1
->time_base
.den
== av
->time_base
.den
&&
3202 av1
->time_base
.num
== av
->time_base
.num
&&
3203 av1
->gop_size
== av
->gop_size
)
3212 fst
= add_av_stream1(feed
, av
);
3215 return feed
->nb_streams
- 1;
3220 static void remove_stream(FFStream
*stream
)