Fix typo in libavcodec/opt.h.
[libav.git] / ffserver.c
CommitLineData
85f07f22
FB
1/*
2 * Multiple format streaming server
773a21b8 3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
85f07f22 4 *
b78e7197
DB
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
773a21b8
FB
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
b78e7197 10 * version 2.1 of the License, or (at your option) any later version.
85f07f22 11 *
b78e7197 12 * FFmpeg is distributed in the hope that it will be useful,
85f07f22 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
773a21b8
FB
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
85f07f22 16 *
773a21b8 17 * You should have received a copy of the GNU Lesser General Public
b78e7197 18 * License along with FFmpeg; if not, write to the Free Software
5509bffa 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
85f07f22 20 */
364a9607 21
0f4e8165 22#include "config.h"
3cf9ea7f 23#ifndef HAVE_CLOSESOCKET
0f4e8165
RB
24#define closesocket close
25#endif
26#include <string.h>
27#include <stdlib.h>
245976da
DB
28#include "libavutil/random.h"
29#include "libavutil/avstring.h"
30#include "libavformat/avformat.h"
31#include "libavformat/network.h"
32#include "libavformat/os_support.h"
33#include "libavformat/rtp.h"
34#include "libavformat/rtsp.h"
7ab08864 35#include "libavcodec/opt.h"
85f07f22 36#include <stdarg.h>
85f07f22
FB
37#include <unistd.h>
38#include <fcntl.h>
39#include <sys/ioctl.h>
f8cda19e
LA
40#ifdef HAVE_POLL_H
41#include <poll.h>
b0c858d8 42#endif
85f07f22
FB
43#include <errno.h>
44#include <sys/time.h>
4568325a 45#undef time //needed because HAVE_AV_CONFIG_H is defined on top
85f07f22 46#include <time.h>
5eb765ef 47#include <sys/wait.h>
85f07f22 48#include <signal.h>
18b67ae5 49#ifdef HAVE_DLFCN_H
2effd274 50#include <dlfcn.h>
6638d424 51#endif
2effd274 52
4ce5df08 53#include "cmdutils.h"
85f07f22 54
c367d067
MN
55#undef exit
56
64555bd9 57const char program_name[] = "FFserver";
ea9c581f 58const int program_birth_year = 2000;
86074ed1 59
5a635bc7
SS
60static const OptionDef options[];
61
85f07f22
FB
62/* maximum number of simultaneous HTTP connections */
63#define HTTP_MAX_CONNECTIONS 2000
64
65enum HTTPState {
66 HTTPSTATE_WAIT_REQUEST,
67 HTTPSTATE_SEND_HEADER,
68 HTTPSTATE_SEND_DATA_HEADER,
2effd274 69 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
85f07f22 70 HTTPSTATE_SEND_DATA_TRAILER,
115329f1 71 HTTPSTATE_RECEIVE_DATA,
2effd274 72 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
2effd274
FB
73 HTTPSTATE_READY,
74
75 RTSPSTATE_WAIT_REQUEST,
76 RTSPSTATE_SEND_REPLY,
bc351386 77 RTSPSTATE_SEND_PACKET,
85f07f22
FB
78};
79
9507a12e 80static const char *http_state[] = {
2effd274
FB
81 "HTTP_WAIT_REQUEST",
82 "HTTP_SEND_HEADER",
83
85f07f22
FB
84 "SEND_DATA_HEADER",
85 "SEND_DATA",
86 "SEND_DATA_TRAILER",
87 "RECEIVE_DATA",
88 "WAIT_FEED",
2effd274
FB
89 "READY",
90
91 "RTSP_WAIT_REQUEST",
92 "RTSP_SEND_REPLY",
bc351386 93 "RTSP_SEND_PACKET",
85f07f22
FB
94};
95
cde25790 96#define IOBUFFER_INIT_SIZE 8192
85f07f22 97
85f07f22 98/* timeouts are in ms */
2effd274
FB
99#define HTTP_REQUEST_TIMEOUT (15 * 1000)
100#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
101
85f07f22
FB
102#define SYNC_TIMEOUT (10 * 1000)
103
5eb765ef 104typedef struct {
0c1a9eda 105 int64_t count1, count2;
c3f58185 106 int64_t time1, time2;
5eb765ef
PG
107} DataRateData;
108
85f07f22
FB
109/* context associated with one connection */
110typedef struct HTTPContext {
111 enum HTTPState state;
112 int fd; /* socket file descriptor */
113 struct sockaddr_in from_addr; /* origin */
114 struct pollfd *poll_entry; /* used when polling */
c3f58185 115 int64_t timeout;
0c1a9eda 116 uint8_t *buffer_ptr, *buffer_end;
85f07f22 117 int http_error;
edfdd798 118 int post;
85f07f22 119 struct HTTPContext *next;
42a63c6a 120 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
0c1a9eda 121 int64_t data_count;
85f07f22
FB
122 /* feed input */
123 int feed_fd;
124 /* input format handling */
125 AVFormatContext *fmt_in;
c3f58185 126 int64_t start_time; /* In milliseconds - this wraps fairly often */
0c1a9eda 127 int64_t first_pts; /* initial pts value */
e240a0bb
FB
128 int64_t cur_pts; /* current pts value from the stream in us */
129 int64_t cur_frame_duration; /* duration of the current frame in us */
130 int cur_frame_bytes; /* output frame size, needed to compute
131 the time at which we send each
132 packet */
133 int pts_stream_index; /* stream we choose as clock reference */
134 int64_t cur_clock; /* current clock reference value in us */
85f07f22
FB
135 /* output format handling */
136 struct FFStream *stream;
cde25790
PG
137 /* -1 is invalid stream */
138 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
139 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
140 int switch_pending;
2effd274 141 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
85f07f22 142 int last_packet_sent; /* true if last data packet was sent */
7434ba6d 143 int suppress_log;
5eb765ef 144 DataRateData datarate;
3120d2a2 145 int wmp_client_id;
7434ba6d
PG
146 char protocol[16];
147 char method[16];
148 char url[128];
cde25790 149 int buffer_size;
0c1a9eda 150 uint8_t *buffer;
2effd274
FB
151 int is_packetized; /* if true, the stream is packetized */
152 int packet_stream_index; /* current stream for output in state machine */
115329f1 153
2effd274 154 /* RTSP state specific */
0c1a9eda 155 uint8_t *pb_buffer; /* XXX: use that in all the code */
2effd274
FB
156 ByteIOContext *pb;
157 int seq; /* RTSP sequence number */
115329f1 158
2effd274
FB
159 /* RTP state specific */
160 enum RTSPProtocol rtp_protocol;
161 char session_id[32]; /* session id */
162 AVFormatContext *rtp_ctx[MAX_STREAMS];
e240a0bb 163
bc351386
FB
164 /* RTP/UDP specific */
165 URLContext *rtp_handles[MAX_STREAMS];
166
167 /* RTP/TCP specific */
168 struct HTTPContext *rtsp_c;
169 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
85f07f22
FB
170} HTTPContext;
171
172/* each generated stream is described here */
173enum StreamType {
174 STREAM_TYPE_LIVE,
175 STREAM_TYPE_STATUS,
cde25790 176 STREAM_TYPE_REDIRECT,
85f07f22
FB
177};
178
8256c0a3
PG
179enum IPAddressAction {
180 IP_ALLOW = 1,
181 IP_DENY,
182};
183
184typedef struct IPAddressACL {
185 struct IPAddressACL *next;
186 enum IPAddressAction action;
efa04ce2 187 /* These are in host order */
8256c0a3
PG
188 struct in_addr first;
189 struct in_addr last;
190} IPAddressACL;
191
85f07f22
FB
192/* description of each stream of the ffserver.conf file */
193typedef struct FFStream {
194 enum StreamType stream_type;
195 char filename[1024]; /* stream filename */
2effd274
FB
196 struct FFStream *feed; /* feed we are using (can be null if
197 coming from file) */
e240a0bb
FB
198 AVFormatParameters *ap_in; /* input parameters */
199 AVInputFormat *ifmt; /* if non NULL, force input format */
bd7cf6ad 200 AVOutputFormat *fmt;
8256c0a3 201 IPAddressACL *acl;
85f07f22 202 int nb_streams;
42a63c6a 203 int prebuffer; /* Number of millseconds early to start */
c3f58185 204 int64_t max_time; /* Number of milliseconds to run */
79c4ea3c 205 int send_on_key;
85f07f22
FB
206 AVStream *streams[MAX_STREAMS];
207 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
208 char feed_filename[1024]; /* file name of the feed storage, or
209 input file name for a stream */
2ac887ba
PG
210 char author[512];
211 char title[512];
212 char copyright[512];
213 char comment[512];
cde25790 214 pid_t pid; /* Of ffmpeg process */
5eb765ef 215 time_t pid_start; /* Of ffmpeg process */
cde25790 216 char **child_argv;
85f07f22 217 struct FFStream *next;
177d2564 218 unsigned bandwidth; /* bandwidth, in kbits/s */
2effd274
FB
219 /* RTSP options */
220 char *rtsp_option;
829ac53d
FB
221 /* multicast specific */
222 int is_multicast;
223 struct in_addr multicast_ip;
224 int multicast_port; /* first port used for multicast */
6edd6884
FB
225 int multicast_ttl;
226 int loop; /* if true, send the stream in loops (only meaningful if file) */
829ac53d 227
85f07f22 228 /* feed specific */
2effd274 229 int feed_opened; /* true if someone is writing to the feed */
85f07f22 230 int is_feed; /* true if it is a feed */
e322ea48 231 int readonly; /* True if writing is prohibited to the file */
a6e14edd 232 int conns_served;
0c1a9eda 233 int64_t bytes_served;
6b0bdc75 234 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
8bfb108b 235 int64_t feed_write_index; /* current write position in feed (it wraps around) */
0c1a9eda 236 int64_t feed_size; /* current size of feed */
85f07f22
FB
237 struct FFStream *next_feed;
238} FFStream;
239
240typedef struct FeedData {
241 long long data_count;
8bfb108b 242 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
85f07f22
FB
243} FeedData;
244
18405874
AB
245static struct sockaddr_in my_http_addr;
246static struct sockaddr_in my_rtsp_addr;
2effd274 247
33f5e2ec
AB
248static char logfilename[1024];
249static HTTPContext *first_http_ctx;
250static FFStream *first_feed; /* contains only feeds */
251static FFStream *first_stream; /* contains all streams, including feeds */
85f07f22 252
2effd274
FB
253static void new_connection(int server_fd, int is_rtsp);
254static void close_connection(HTTPContext *c);
255
256/* HTTP handling */
257static int handle_connection(HTTPContext *c);
85f07f22 258static int http_parse_request(HTTPContext *c);
5eb765ef 259static int http_send_data(HTTPContext *c);
dca21085 260static void compute_status(HTTPContext *c);
85f07f22
FB
261static int open_input_stream(HTTPContext *c, const char *info);
262static int http_start_receive_data(HTTPContext *c);
263static int http_receive_data(HTTPContext *c);
2effd274
FB
264
265/* RTSP handling */
266static int rtsp_parse_request(HTTPContext *c);
267static void rtsp_cmd_describe(HTTPContext *c, const char *url);
0df65975 268static void rtsp_cmd_options(HTTPContext *c, const char *url);
2effd274
FB
269static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPHeader *h);
270static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h);
271static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h);
272static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h);
273
829ac53d 274/* SDP handling */
115329f1 275static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d
FB
276 struct in_addr my_ip);
277
2effd274 278/* RTP handling */
115329f1 279static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
bc351386
FB
280 FFStream *stream, const char *session_id,
281 enum RTSPProtocol rtp_protocol);
115329f1 282static int rtp_new_av_stream(HTTPContext *c,
bc351386
FB
283 int stream_index, struct sockaddr_in *dest_addr,
284 HTTPContext *rtsp_c);
85f07f22 285
cde25790 286static const char *my_program_name;
d6562d2c 287static const char *my_program_dir;
cde25790 288
5a635bc7 289static const char *config_filename;
2ac887ba 290static int ffserver_debug;
2effd274 291static int ffserver_daemon;
2ac887ba 292static int no_launch;
5eb765ef 293static int need_to_start_children;
2ac887ba 294
f69bb0cc 295static int nb_max_connections = 5;
33f5e2ec 296static int nb_connections;
85f07f22 297
f69bb0cc 298static uint64_t max_bandwidth = 1000;
1ad8289e 299static uint64_t current_bandwidth;
42a63c6a 300
c3f58185 301static int64_t cur_time; // Making this global saves on passing it around everywhere
5eb765ef 302
1df93ae9
AB
303static AVRandomState random_state;
304
85f07f22
FB
305static FILE *logfile = NULL;
306
9fd3442f
BC
307static char *ctime1(char *buf2)
308{
309 time_t ti;
310 char *p;
311
312 ti = time(NULL);
313 p = ctime(&ti);
314 strcpy(buf2, p);
315 p = buf2 + strlen(p) - 1;
316 if (*p == '\n')
317 *p = '\0';
318 return buf2;
319}
320
bcd3ce59 321static void http_vlog(const char *fmt, va_list vargs)
85f07f22 322{
124ed1c0 323 static int print_prefix = 1;
7434ba6d 324 if (logfile) {
124ed1c0 325 if (print_prefix) {
9fd3442f
BC
326 char buf[32];
327 ctime1(buf);
328 fprintf(logfile, "%s ", buf);
124ed1c0
BC
329 }
330 print_prefix = strstr(fmt, "\n") != NULL;
bcd3ce59 331 vfprintf(logfile, fmt, vargs);
7434ba6d
PG
332 fflush(logfile);
333 }
bcd3ce59
BC
334}
335
336void __attribute__ ((format (printf, 1, 2))) http_log(const char *fmt, ...)
337{
338 va_list vargs;
339 va_start(vargs, fmt);
340 http_vlog(fmt, vargs);
341 va_end(vargs);
342}
343
344static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
345{
346 static int print_prefix = 1;
347 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
348 if (level > av_log_level)
349 return;
350 if (print_prefix && avc)
351 http_log("[%s @ %p]", avc->item_name(ptr), avc);
352 print_prefix = strstr(fmt, "\n") != NULL;
353 http_vlog(fmt, vargs);
85f07f22
FB
354}
355
6edd6884
FB
356static void log_connection(HTTPContext *c)
357{
115329f1 358 if (c->suppress_log)
6edd6884
FB
359 return;
360
82e0be62
BC
361 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
362 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
6edd6884 363 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
cde25790
PG
364}
365
0c1a9eda 366static void update_datarate(DataRateData *drd, int64_t count)
5eb765ef
PG
367{
368 if (!drd->time1 && !drd->count1) {
369 drd->time1 = drd->time2 = cur_time;
370 drd->count1 = drd->count2 = count;
eeffbdea 371 } else if (cur_time - drd->time2 > 5000) {
33a4ecbe
AB
372 drd->time1 = drd->time2;
373 drd->count1 = drd->count2;
374 drd->time2 = cur_time;
375 drd->count2 = count;
5eb765ef
PG
376 }
377}
378
379/* In bytes per second */
0c1a9eda 380static int compute_datarate(DataRateData *drd, int64_t count)
5eb765ef
PG
381{
382 if (cur_time == drd->time1)
383 return 0;
115329f1 384
5eb765ef
PG
385 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
386}
387
a782f209 388
cde25790
PG
389static void start_children(FFStream *feed)
390{
2ac887ba
PG
391 if (no_launch)
392 return;
393
cde25790 394 for (; feed; feed = feed->next) {
5eb765ef
PG
395 if (feed->child_argv && !feed->pid) {
396 feed->pid_start = time(0);
397
cde25790
PG
398 feed->pid = fork();
399
400 if (feed->pid < 0) {
b4befb99 401 http_log("Unable to create children\n");
cde25790
PG
402 exit(1);
403 }
404 if (!feed->pid) {
405 /* In child */
406 char pathname[1024];
407 char *slash;
408 int i;
409
611c5741 410 for (i = 3; i < 256; i++)
5eb765ef 411 close(i);
cde25790 412
5eb765ef 413 if (!ffserver_debug) {
2ac887ba 414 i = open("/dev/null", O_RDWR);
3296409d 415 if (i != -1) {
2ac887ba 416 dup2(i, 0);
3296409d
BC
417 dup2(i, 1);
418 dup2(i, 2);
5eb765ef 419 close(i);
3296409d 420 }
2ac887ba 421 }
cde25790 422
f7d78f36 423 av_strlcpy(pathname, my_program_name, sizeof(pathname));
cde25790
PG
424
425 slash = strrchr(pathname, '/');
611c5741 426 if (!slash)
cde25790 427 slash = pathname;
611c5741 428 else
cde25790 429 slash++;
cde25790
PG
430 strcpy(slash, "ffmpeg");
431
d6562d2c
PG
432 /* This is needed to make relative pathnames work */
433 chdir(my_program_dir);
434
a4d70941
PG
435 signal(SIGPIPE, SIG_DFL);
436
cde25790
PG
437 execvp(pathname, feed->child_argv);
438
439 _exit(1);
440 }
441 }
442 }
7434ba6d
PG
443}
444
2effd274
FB
445/* open a listening socket */
446static int socket_open_listen(struct sockaddr_in *my_addr)
85f07f22 447{
2effd274 448 int server_fd, tmp;
85f07f22
FB
449
450 server_fd = socket(AF_INET,SOCK_STREAM,0);
451 if (server_fd < 0) {
452 perror ("socket");
453 return -1;
454 }
115329f1 455
85f07f22
FB
456 tmp = 1;
457 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
458
2effd274 459 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
b17d099d
PG
460 char bindmsg[32];
461 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
462 perror (bindmsg);
d96633bb 463 closesocket(server_fd);
85f07f22
FB
464 return -1;
465 }
115329f1 466
85f07f22
FB
467 if (listen (server_fd, 5) < 0) {
468 perror ("listen");
d96633bb 469 closesocket(server_fd);
85f07f22
FB
470 return -1;
471 }
ba472aaf 472 ff_socket_nonblock(server_fd, 1);
2effd274
FB
473
474 return server_fd;
475}
476
6edd6884
FB
477/* start all multicast streams */
478static void start_multicast(void)
479{
480 FFStream *stream;
481 char session_id[32];
482 HTTPContext *rtp_c;
483 struct sockaddr_in dest_addr;
484 int default_port, stream_index;
485
486 default_port = 6000;
487 for(stream = first_stream; stream != NULL; stream = stream->next) {
488 if (stream->is_multicast) {
489 /* open the RTP connection */
1df93ae9
AB
490 snprintf(session_id, sizeof(session_id), "%08x%08x",
491 av_random(&random_state), av_random(&random_state));
6edd6884
FB
492
493 /* choose a port if none given */
494 if (stream->multicast_port == 0) {
495 stream->multicast_port = default_port;
496 default_port += 100;
497 }
498
499 dest_addr.sin_family = AF_INET;
500 dest_addr.sin_addr = stream->multicast_ip;
501 dest_addr.sin_port = htons(stream->multicast_port);
502
115329f1 503 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
bc351386 504 RTSP_PROTOCOL_RTP_UDP_MULTICAST);
611c5741 505 if (!rtp_c)
6edd6884 506 continue;
611c5741 507
6edd6884 508 if (open_input_stream(rtp_c, "") < 0) {
b4befb99
BC
509 http_log("Could not open input stream for stream '%s'\n",
510 stream->filename);
6edd6884
FB
511 continue;
512 }
513
6edd6884 514 /* open each RTP stream */
115329f1 515 for(stream_index = 0; stream_index < stream->nb_streams;
6edd6884 516 stream_index++) {
115329f1 517 dest_addr.sin_port = htons(stream->multicast_port +
6edd6884 518 2 * stream_index);
bc351386 519 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
b4befb99
BC
520 http_log("Could not open output stream '%s/streamid=%d'\n",
521 stream->filename, stream_index);
0fa45e19 522 exit(1);
6edd6884
FB
523 }
524 }
525
526 /* change state to send data */
527 rtp_c->state = HTTPSTATE_SEND_DATA;
528 }
529 }
530}
2effd274
FB
531
532/* main loop of the http server */
533static int http_server(void)
534{
d2a1ea1d
BC
535 int server_fd = 0, rtsp_server_fd = 0;
536 int ret, delay, delay1;
2effd274
FB
537 struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry;
538 HTTPContext *c, *c_next;
539
d2a1ea1d 540 if (my_http_addr.sin_port) {
2b9cd1e7
BC
541 server_fd = socket_open_listen(&my_http_addr);
542 if (server_fd < 0)
543 return -1;
d2a1ea1d 544 }
85f07f22 545
d2a1ea1d 546 if (my_rtsp_addr.sin_port) {
2b9cd1e7
BC
547 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
548 if (rtsp_server_fd < 0)
549 return -1;
d2a1ea1d
BC
550 }
551
552 if (!rtsp_server_fd && !server_fd) {
553 http_log("HTTP and RTSP disabled.\n");
554 return -1;
555 }
115329f1 556
85f07f22
FB
557 http_log("ffserver started.\n");
558
cde25790
PG
559 start_children(first_feed);
560
85f07f22
FB
561 first_http_ctx = NULL;
562 nb_connections = 0;
6edd6884
FB
563
564 start_multicast();
565
85f07f22
FB
566 for(;;) {
567 poll_entry = poll_table;
d2a1ea1d 568 if (server_fd) {
2b9cd1e7
BC
569 poll_entry->fd = server_fd;
570 poll_entry->events = POLLIN;
571 poll_entry++;
d2a1ea1d
BC
572 }
573 if (rtsp_server_fd) {
2b9cd1e7
BC
574 poll_entry->fd = rtsp_server_fd;
575 poll_entry->events = POLLIN;
576 poll_entry++;
d2a1ea1d 577 }
2effd274 578
85f07f22
FB
579 /* wait for events on each HTTP handle */
580 c = first_http_ctx;
2effd274 581 delay = 1000;
85f07f22
FB
582 while (c != NULL) {
583 int fd;
584 fd = c->fd;
585 switch(c->state) {
2effd274
FB
586 case HTTPSTATE_SEND_HEADER:
587 case RTSPSTATE_SEND_REPLY:
bc351386 588 case RTSPSTATE_SEND_PACKET:
85f07f22
FB
589 c->poll_entry = poll_entry;
590 poll_entry->fd = fd;
2effd274 591 poll_entry->events = POLLOUT;
85f07f22
FB
592 poll_entry++;
593 break;
85f07f22
FB
594 case HTTPSTATE_SEND_DATA_HEADER:
595 case HTTPSTATE_SEND_DATA:
596 case HTTPSTATE_SEND_DATA_TRAILER:
2effd274
FB
597 if (!c->is_packetized) {
598 /* for TCP, we output as much as we can (may need to put a limit) */
599 c->poll_entry = poll_entry;
600 poll_entry->fd = fd;
601 poll_entry->events = POLLOUT;
602 poll_entry++;
603 } else {
e240a0bb
FB
604 /* when ffserver is doing the timing, we work by
605 looking at which packet need to be sent every
606 10 ms */
607 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
608 if (delay1 < delay)
609 delay = delay1;
2effd274 610 }
85f07f22 611 break;
2effd274 612 case HTTPSTATE_WAIT_REQUEST:
85f07f22 613 case HTTPSTATE_RECEIVE_DATA:
85f07f22 614 case HTTPSTATE_WAIT_FEED:
2effd274 615 case RTSPSTATE_WAIT_REQUEST:
85f07f22
FB
616 /* need to catch errors */
617 c->poll_entry = poll_entry;
618 poll_entry->fd = fd;
a6e14edd 619 poll_entry->events = POLLIN;/* Maybe this will work */
85f07f22
FB
620 poll_entry++;
621 break;
622 default:
623 c->poll_entry = NULL;
624 break;
625 }
626 c = c->next;
627 }
628
629 /* wait for an event on one connection. We poll at least every
630 second to handle timeouts */
631 do {
2effd274 632 ret = poll(poll_table, poll_entry - poll_table, delay);
8da4034f
AB
633 if (ret < 0 && ff_neterrno() != FF_NETERROR(EAGAIN) &&
634 ff_neterrno() != FF_NETERROR(EINTR))
53e2f9ca 635 return -1;
e8d658df 636 } while (ret < 0);
115329f1 637
c3f58185 638 cur_time = av_gettime() / 1000;
85f07f22 639
5eb765ef
PG
640 if (need_to_start_children) {
641 need_to_start_children = 0;
642 start_children(first_feed);
643 }
644
85f07f22 645 /* now handle the events */
2effd274
FB
646 for(c = first_http_ctx; c != NULL; c = c_next) {
647 c_next = c->next;
648 if (handle_connection(c) < 0) {
85f07f22 649 /* close and free the connection */
7434ba6d 650 log_connection(c);
2effd274 651 close_connection(c);
85f07f22
FB
652 }
653 }
654
85f07f22 655 poll_entry = poll_table;
d2a1ea1d 656 if (server_fd) {
2b9cd1e7
BC
657 /* new HTTP connection request ? */
658 if (poll_entry->revents & POLLIN)
659 new_connection(server_fd, 0);
660 poll_entry++;
d2a1ea1d
BC
661 }
662 if (rtsp_server_fd) {
2b9cd1e7
BC
663 /* new RTSP connection request ? */
664 if (poll_entry->revents & POLLIN)
665 new_connection(rtsp_server_fd, 1);
d2a1ea1d 666 }
85f07f22
FB
667 }
668}
669
2effd274
FB
670/* start waiting for a new HTTP/RTSP request */
671static void start_wait_request(HTTPContext *c, int is_rtsp)
85f07f22 672{
2effd274
FB
673 c->buffer_ptr = c->buffer;
674 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
675
676 if (is_rtsp) {
677 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
678 c->state = RTSPSTATE_WAIT_REQUEST;
679 } else {
680 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
681 c->state = HTTPSTATE_WAIT_REQUEST;
682 }
683}
684
685static void new_connection(int server_fd, int is_rtsp)
686{
687 struct sockaddr_in from_addr;
688 int fd, len;
689 HTTPContext *c = NULL;
690
691 len = sizeof(from_addr);
115329f1 692 fd = accept(server_fd, (struct sockaddr *)&from_addr,
2effd274 693 &len);
050056d0
BC
694 if (fd < 0) {
695 http_log("error during accept %s\n", strerror(errno));
2effd274 696 return;
050056d0 697 }
ba472aaf 698 ff_socket_nonblock(fd, 1);
2effd274
FB
699
700 /* XXX: should output a warning page when coming
701 close to the connection limit */
702 if (nb_connections >= nb_max_connections)
703 goto fail;
115329f1 704
2effd274
FB
705 /* add a new connection */
706 c = av_mallocz(sizeof(HTTPContext));
707 if (!c)
708 goto fail;
115329f1 709
2effd274
FB
710 c->fd = fd;
711 c->poll_entry = NULL;
712 c->from_addr = from_addr;
713 c->buffer_size = IOBUFFER_INIT_SIZE;
714 c->buffer = av_malloc(c->buffer_size);
715 if (!c->buffer)
716 goto fail;
8bc80f8b
PG
717
718 c->next = first_http_ctx;
719 first_http_ctx = c;
2effd274 720 nb_connections++;
115329f1 721
2effd274
FB
722 start_wait_request(c, is_rtsp);
723
724 return;
725
726 fail:
727 if (c) {
728 av_free(c->buffer);
729 av_free(c);
730 }
d96633bb 731 closesocket(fd);
2effd274
FB
732}
733
734static void close_connection(HTTPContext *c)
735{
736 HTTPContext **cp, *c1;
737 int i, nb_streams;
738 AVFormatContext *ctx;
739 URLContext *h;
740 AVStream *st;
741
742 /* remove connection from list */
743 cp = &first_http_ctx;
744 while ((*cp) != NULL) {
745 c1 = *cp;
611c5741 746 if (c1 == c)
2effd274 747 *cp = c->next;
611c5741 748 else
2effd274 749 cp = &c1->next;
2effd274
FB
750 }
751
bc351386
FB
752 /* remove references, if any (XXX: do it faster) */
753 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
754 if (c1->rtsp_c == c)
755 c1->rtsp_c = NULL;
756 }
757
2effd274
FB
758 /* remove connection associated resources */
759 if (c->fd >= 0)
d96633bb 760 closesocket(c->fd);
2effd274
FB
761 if (c->fmt_in) {
762 /* close each frame parser */
763 for(i=0;i<c->fmt_in->nb_streams;i++) {
764 st = c->fmt_in->streams[i];
611c5741 765 if (st->codec->codec)
01f4895c 766 avcodec_close(st->codec);
2effd274
FB
767 }
768 av_close_input_file(c->fmt_in);
769 }
770
771 /* free RTP output streams if any */
772 nb_streams = 0;
115329f1 773 if (c->stream)
2effd274 774 nb_streams = c->stream->nb_streams;
115329f1 775
2effd274
FB
776 for(i=0;i<nb_streams;i++) {
777 ctx = c->rtp_ctx[i];
778 if (ctx) {
779 av_write_trailer(ctx);
780 av_free(ctx);
781 }
782 h = c->rtp_handles[i];
611c5741 783 if (h)
2effd274 784 url_close(h);
2effd274 785 }
115329f1 786
b88ba823
MH
787 ctx = &c->fmt_ctx;
788
87638494 789 if (!c->last_packet_sent) {
87638494
PG
790 if (ctx->oformat) {
791 /* prepare header */
792 if (url_open_dyn_buf(&ctx->pb) >= 0) {
793 av_write_trailer(ctx);
f8b06be9 794 av_freep(&c->pb_buffer);
899681cd 795 url_close_dyn_buf(ctx->pb, &c->pb_buffer);
87638494
PG
796 }
797 }
798 }
799
115329f1 800 for(i=0; i<ctx->nb_streams; i++)
0bd53967 801 av_free(ctx->streams[i]);
f0ef6240 802
edfdd798 803 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
6edd6884 804 current_bandwidth -= c->stream->bandwidth;
5400e092
AB
805
806 /* signal that there is no feed if we are the feeder socket */
807 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
808 c->stream->feed_opened = 0;
809 close(c->feed_fd);
810 }
811
2effd274 812 av_freep(&c->pb_buffer);
bc351386 813 av_freep(&c->packet_buffer);
2effd274
FB
814 av_free(c->buffer);
815 av_free(c);
816 nb_connections--;
817}
818
819static int handle_connection(HTTPContext *c)
820{
821 int len, ret;
115329f1 822
85f07f22
FB
823 switch(c->state) {
824 case HTTPSTATE_WAIT_REQUEST:
2effd274 825 case RTSPSTATE_WAIT_REQUEST:
85f07f22
FB
826 /* timeout ? */
827 if ((c->timeout - cur_time) < 0)
828 return -1;
829 if (c->poll_entry->revents & (POLLERR | POLLHUP))
830 return -1;
831
832 /* no need to read if no events */
833 if (!(c->poll_entry->revents & POLLIN))
834 return 0;
835 /* read the data */
1bc1cfdd 836 read_loop:
c60202df 837 len = recv(c->fd, c->buffer_ptr, 1, 0);
85f07f22 838 if (len < 0) {
8da4034f
AB
839 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
840 ff_neterrno() != FF_NETERROR(EINTR))
85f07f22
FB
841 return -1;
842 } else if (len == 0) {
843 return -1;
844 } else {
94d9ad5f 845 /* search for end of request. */
0c1a9eda 846 uint8_t *ptr;
85f07f22
FB
847 c->buffer_ptr += len;
848 ptr = c->buffer_ptr;
849 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
850 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
851 /* request found : parse it and reply */
2effd274
FB
852 if (c->state == HTTPSTATE_WAIT_REQUEST) {
853 ret = http_parse_request(c);
854 } else {
855 ret = rtsp_parse_request(c);
856 }
857 if (ret < 0)
85f07f22
FB
858 return -1;
859 } else if (ptr >= c->buffer_end) {
860 /* request too long: cannot do anything */
861 return -1;
1bc1cfdd 862 } else goto read_loop;
85f07f22
FB
863 }
864 break;
865
866 case HTTPSTATE_SEND_HEADER:
867 if (c->poll_entry->revents & (POLLERR | POLLHUP))
868 return -1;
869
2effd274 870 /* no need to write if no events */
85f07f22
FB
871 if (!(c->poll_entry->revents & POLLOUT))
872 return 0;
c60202df 873 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
85f07f22 874 if (len < 0) {
8da4034f
AB
875 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
876 ff_neterrno() != FF_NETERROR(EINTR)) {
85f07f22 877 /* error : close connection */
2effd274 878 av_freep(&c->pb_buffer);
85f07f22
FB
879 return -1;
880 }
881 } else {
882 c->buffer_ptr += len;
2e04edb3
PG
883 if (c->stream)
884 c->stream->bytes_served += len;
a6e14edd 885 c->data_count += len;
85f07f22 886 if (c->buffer_ptr >= c->buffer_end) {
2effd274 887 av_freep(&c->pb_buffer);
85f07f22 888 /* if error, exit */
611c5741 889 if (c->http_error)
85f07f22 890 return -1;
2effd274 891 /* all the buffer was sent : synchronize to the incoming stream */
85f07f22
FB
892 c->state = HTTPSTATE_SEND_DATA_HEADER;
893 c->buffer_ptr = c->buffer_end = c->buffer;
894 }
895 }
896 break;
897
898 case HTTPSTATE_SEND_DATA:
899 case HTTPSTATE_SEND_DATA_HEADER:
900 case HTTPSTATE_SEND_DATA_TRAILER:
2effd274
FB
901 /* for packetized output, we consider we can always write (the
902 input streams sets the speed). It may be better to verify
903 that we do not rely too much on the kernel queues */
904 if (!c->is_packetized) {
905 if (c->poll_entry->revents & (POLLERR | POLLHUP))
906 return -1;
115329f1 907
2effd274
FB
908 /* no need to read if no events */
909 if (!(c->poll_entry->revents & POLLOUT))
910 return 0;
911 }
5eb765ef 912 if (http_send_data(c) < 0)
85f07f22 913 return -1;
638831aa
AB
914 /* close connection if trailer sent */
915 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
916 return -1;
85f07f22
FB
917 break;
918 case HTTPSTATE_RECEIVE_DATA:
919 /* no need to read if no events */
920 if (c->poll_entry->revents & (POLLERR | POLLHUP))
921 return -1;
922 if (!(c->poll_entry->revents & POLLIN))
923 return 0;
924 if (http_receive_data(c) < 0)
925 return -1;
926 break;
927 case HTTPSTATE_WAIT_FEED:
928 /* no need to read if no events */
a6e14edd 929 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
85f07f22
FB
930 return -1;
931
932 /* nothing to do, we'll be waken up by incoming feed packets */
933 break;
2effd274 934
2effd274
FB
935 case RTSPSTATE_SEND_REPLY:
936 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
937 av_freep(&c->pb_buffer);
938 return -1;
939 }
940 /* no need to write if no events */
941 if (!(c->poll_entry->revents & POLLOUT))
942 return 0;
c60202df 943 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2effd274 944 if (len < 0) {
8da4034f
AB
945 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
946 ff_neterrno() != FF_NETERROR(EINTR)) {
2effd274
FB
947 /* error : close connection */
948 av_freep(&c->pb_buffer);
949 return -1;
950 }
951 } else {
952 c->buffer_ptr += len;
953 c->data_count += len;
954 if (c->buffer_ptr >= c->buffer_end) {
955 /* all the buffer was sent : wait for a new request */
956 av_freep(&c->pb_buffer);
957 start_wait_request(c, 1);
958 }
959 }
960 break;
bc351386
FB
961 case RTSPSTATE_SEND_PACKET:
962 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
963 av_freep(&c->packet_buffer);
964 return -1;
965 }
966 /* no need to write if no events */
967 if (!(c->poll_entry->revents & POLLOUT))
968 return 0;
c60202df
AB
969 len = send(c->fd, c->packet_buffer_ptr,
970 c->packet_buffer_end - c->packet_buffer_ptr, 0);
bc351386 971 if (len < 0) {
8da4034f
AB
972 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
973 ff_neterrno() != FF_NETERROR(EINTR)) {
bc351386
FB
974 /* error : close connection */
975 av_freep(&c->packet_buffer);
976 return -1;
977 }
978 } else {
979 c->packet_buffer_ptr += len;
980 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
981 /* all the buffer was sent : wait for a new request */
982 av_freep(&c->packet_buffer);
983 c->state = RTSPSTATE_WAIT_REQUEST;
984 }
985 }
986 break;
2effd274
FB
987 case HTTPSTATE_READY:
988 /* nothing to do */
989 break;
85f07f22
FB
990 default:
991 return -1;
992 }
993 return 0;
994}
995
3120d2a2
PG
996static int extract_rates(char *rates, int ratelen, const char *request)
997{
998 const char *p;
999
1000 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1001 if (strncasecmp(p, "Pragma:", 7) == 0) {
1002 const char *q = p + 7;
1003
1004 while (*q && *q != '\n' && isspace(*q))
1005 q++;
1006
1007 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1008 int stream_no;
1009 int rate_no;
1010
1011 q += 20;
1012
cde25790 1013 memset(rates, 0xff, ratelen);
3120d2a2
PG
1014
1015 while (1) {
1016 while (*q && *q != '\n' && *q != ':')
1017 q++;
1018
611c5741 1019 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
3120d2a2 1020 break;
611c5741 1021
3120d2a2 1022 stream_no--;
611c5741 1023 if (stream_no < ratelen && stream_no >= 0)
3120d2a2 1024 rates[stream_no] = rate_no;
3120d2a2
PG
1025
1026 while (*q && *q != '\n' && !isspace(*q))
1027 q++;
1028 }
1029
1030 return 1;
1031 }
1032 }
1033 p = strchr(p, '\n');
1034 if (!p)
1035 break;
1036
1037 p++;
1038 }
1039
1040 return 0;
1041}
1042
cde25790 1043static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
3120d2a2
PG
1044{
1045 int i;
cde25790
PG
1046 int best_bitrate = 100000000;
1047 int best = -1;
1048
1049 for (i = 0; i < feed->nb_streams; i++) {
01f4895c 1050 AVCodecContext *feed_codec = feed->streams[i]->codec;
cde25790
PG
1051
1052 if (feed_codec->codec_id != codec->codec_id ||
1053 feed_codec->sample_rate != codec->sample_rate ||
1054 feed_codec->width != codec->width ||
611c5741 1055 feed_codec->height != codec->height)
cde25790 1056 continue;
cde25790
PG
1057
1058 /* Potential stream */
1059
115329f1 1060 /* We want the fastest stream less than bit_rate, or the slowest
cde25790
PG
1061 * faster than bit_rate
1062 */
1063
1064 if (feed_codec->bit_rate <= bit_rate) {
1065 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1066 best_bitrate = feed_codec->bit_rate;
1067 best = i;
1068 }
1069 } else {
1070 if (feed_codec->bit_rate < best_bitrate) {
1071 best_bitrate = feed_codec->bit_rate;
1072 best = i;
1073 }
1074 }
1075 }
1076
1077 return best;
1078}
1079
1080static int modify_current_stream(HTTPContext *c, char *rates)
1081{
1082 int i;
1083 FFStream *req = c->stream;
1084 int action_required = 0;
3120d2a2 1085
001bcd29
PG
1086 /* Not much we can do for a feed */
1087 if (!req->feed)
1088 return 0;
1089
3120d2a2 1090 for (i = 0; i < req->nb_streams; i++) {
01f4895c 1091 AVCodecContext *codec = req->streams[i]->codec;
3120d2a2 1092
3120d2a2
PG
1093 switch(rates[i]) {
1094 case 0:
cde25790 1095 c->switch_feed_streams[i] = req->feed_streams[i];
3120d2a2
PG
1096 break;
1097 case 1:
cde25790 1098 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
3120d2a2
PG
1099 break;
1100 case 2:
cde25790
PG
1101 /* Wants off or slow */
1102 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1103#ifdef WANTS_OFF
1104 /* This doesn't work well when it turns off the only stream! */
1105 c->switch_feed_streams[i] = -2;
1106 c->feed_streams[i] = -2;
1107#endif
3120d2a2
PG
1108 break;
1109 }
3120d2a2 1110
cde25790
PG
1111 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1112 action_required = 1;
1113 }
3120d2a2 1114
cde25790
PG
1115 return action_required;
1116}
3120d2a2 1117
3120d2a2 1118
cde25790
PG
1119static void do_switch_stream(HTTPContext *c, int i)
1120{
1121 if (c->switch_feed_streams[i] >= 0) {
115329f1 1122#ifdef PHILIP
cde25790
PG
1123 c->feed_streams[i] = c->switch_feed_streams[i];
1124#endif
3120d2a2 1125
cde25790 1126 /* Now update the stream */
3120d2a2 1127 }
cde25790 1128 c->switch_feed_streams[i] = -1;
3120d2a2 1129}
7434ba6d 1130
2effd274
FB
1131/* XXX: factorize in utils.c ? */
1132/* XXX: take care with different space meaning */
1133static void skip_spaces(const char **pp)
1134{
1135 const char *p;
1136 p = *pp;
1137 while (*p == ' ' || *p == '\t')
1138 p++;
1139 *pp = p;
1140}
1141
1142static void get_word(char *buf, int buf_size, const char **pp)
1143{
1144 const char *p;
1145 char *q;
1146
1147 p = *pp;
1148 skip_spaces(&p);
1149 q = buf;
1150 while (!isspace(*p) && *p != '\0') {
1151 if ((q - buf) < buf_size - 1)
1152 *q++ = *p;
1153 p++;
1154 }
1155 if (buf_size > 0)
1156 *q = '\0';
1157 *pp = p;
1158}
1159
8256c0a3
PG
1160static int validate_acl(FFStream *stream, HTTPContext *c)
1161{
1162 enum IPAddressAction last_action = IP_DENY;
1163 IPAddressACL *acl;
1164 struct in_addr *src = &c->from_addr.sin_addr;
2bd8416e 1165 unsigned long src_addr = src->s_addr;
8256c0a3
PG
1166
1167 for (acl = stream->acl; acl; acl = acl->next) {
611c5741 1168 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
8256c0a3 1169 return (acl->action == IP_ALLOW) ? 1 : 0;
8256c0a3
PG
1170 last_action = acl->action;
1171 }
1172
1173 /* Nothing matched, so return not the last action */
1174 return (last_action == IP_DENY) ? 1 : 0;
1175}
1176
829ac53d
FB
1177/* compute the real filename of a file by matching it without its
1178 extensions to all the stream filenames */
1179static void compute_real_filename(char *filename, int max_size)
1180{
1181 char file1[1024];
1182 char file2[1024];
1183 char *p;
1184 FFStream *stream;
1185
1186 /* compute filename by matching without the file extensions */
f7d78f36 1187 av_strlcpy(file1, filename, sizeof(file1));
829ac53d
FB
1188 p = strrchr(file1, '.');
1189 if (p)
1190 *p = '\0';
1191 for(stream = first_stream; stream != NULL; stream = stream->next) {
f7d78f36 1192 av_strlcpy(file2, stream->filename, sizeof(file2));
829ac53d
FB
1193 p = strrchr(file2, '.');
1194 if (p)
1195 *p = '\0';
1196 if (!strcmp(file1, file2)) {
f7d78f36 1197 av_strlcpy(filename, stream->filename, max_size);
829ac53d
FB
1198 break;
1199 }
1200 }
1201}
1202
1203enum RedirType {
1204 REDIR_NONE,
1205 REDIR_ASX,
1206 REDIR_RAM,
1207 REDIR_ASF,
1208 REDIR_RTSP,
1209 REDIR_SDP,
1210};
1211
85f07f22
FB
1212/* parse http request and prepare header */
1213static int http_parse_request(HTTPContext *c)
1214{
1215 char *p;
829ac53d 1216 enum RedirType redir_type;
85f07f22 1217 char cmd[32];
bae79c04 1218 char info[1024], filename[1024];
85f07f22
FB
1219 char url[1024], *q;
1220 char protocol[32];
1221 char msg[1024];
1222 const char *mime_type;
1223 FFStream *stream;
42a63c6a 1224 int i;
3120d2a2 1225 char ratebuf[32];
cde25790 1226 char *useragent = 0;
85f07f22
FB
1227
1228 p = c->buffer;
2effd274 1229 get_word(cmd, sizeof(cmd), (const char **)&p);
f7d78f36 1230 av_strlcpy(c->method, cmd, sizeof(c->method));
7434ba6d 1231
85f07f22 1232 if (!strcmp(cmd, "GET"))
edfdd798 1233 c->post = 0;
85f07f22 1234 else if (!strcmp(cmd, "POST"))
edfdd798 1235 c->post = 1;
85f07f22
FB
1236 else
1237 return -1;
1238
2effd274 1239 get_word(url, sizeof(url), (const char **)&p);
f7d78f36 1240 av_strlcpy(c->url, url, sizeof(c->url));
7434ba6d 1241
2effd274 1242 get_word(protocol, sizeof(protocol), (const char **)&p);
85f07f22
FB
1243 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1244 return -1;
7434ba6d 1245
f7d78f36 1246 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
90f9c440
AB
1247
1248 if (ffserver_debug)
bb270c08 1249 http_log("New connection: %s %s\n", cmd, url);
115329f1 1250
85f07f22 1251 /* find the filename and the optional info string in the request */
bae79c04 1252 p = strchr(url, '?');
85f07f22 1253 if (p) {
f7d78f36 1254 av_strlcpy(info, p, sizeof(info));
85f07f22 1255 *p = '\0';
611c5741 1256 } else
85f07f22 1257 info[0] = '\0';
85f07f22 1258
f7d78f36 1259 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
bae79c04 1260
cde25790
PG
1261 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1262 if (strncasecmp(p, "User-Agent:", 11) == 0) {
1263 useragent = p + 11;
1264 if (*useragent && *useragent != '\n' && isspace(*useragent))
1265 useragent++;
1266 break;
1267 }
1268 p = strchr(p, '\n');
1269 if (!p)
1270 break;
1271
1272 p++;
1273 }
1274
829ac53d
FB
1275 redir_type = REDIR_NONE;
1276 if (match_ext(filename, "asx")) {
1277 redir_type = REDIR_ASX;
7434ba6d 1278 filename[strlen(filename)-1] = 'f';
c2ce254c 1279 } else if (match_ext(filename, "asf") &&
cde25790
PG
1280 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1281 /* if this isn't WMP or lookalike, return the redirector file */
829ac53d
FB
1282 redir_type = REDIR_ASF;
1283 } else if (match_ext(filename, "rpm,ram")) {
1284 redir_type = REDIR_RAM;
42a63c6a 1285 strcpy(filename + strlen(filename)-2, "m");
829ac53d
FB
1286 } else if (match_ext(filename, "rtsp")) {
1287 redir_type = REDIR_RTSP;
bae79c04 1288 compute_real_filename(filename, sizeof(filename) - 1);
829ac53d
FB
1289 } else if (match_ext(filename, "sdp")) {
1290 redir_type = REDIR_SDP;
bae79c04 1291 compute_real_filename(filename, sizeof(filename) - 1);
42a63c6a 1292 }
115329f1 1293
bae79c04
AB
1294 // "redirect" / request to index.html
1295 if (!strlen(filename))
f7d78f36 1296 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
bae79c04 1297
85f07f22
FB
1298 stream = first_stream;
1299 while (stream != NULL) {
8256c0a3 1300 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
85f07f22
FB
1301 break;
1302 stream = stream->next;
1303 }
1304 if (stream == NULL) {
d445a7e9 1305 snprintf(msg, sizeof(msg), "File '%s' not found", url);
85f07f22
FB
1306 goto send_error;
1307 }
42a63c6a 1308
cde25790
PG
1309 c->stream = stream;
1310 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1311 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1312
1313 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1314 c->http_error = 301;
1315 q = c->buffer;
d445a7e9
PG
1316 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 301 Moved\r\n");
1317 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Location: %s\r\n", stream->feed_filename);
1318 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1319 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1320 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Moved</title></head><body>\r\n");
1321 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
1322 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
cde25790
PG
1323
1324 /* prepare output buffer */
1325 c->buffer_ptr = c->buffer;
1326 c->buffer_end = q;
1327 c->state = HTTPSTATE_SEND_HEADER;
1328 return 0;
1329 }
1330
3120d2a2
PG
1331 /* If this is WMP, get the rate information */
1332 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
cde25790
PG
1333 if (modify_current_stream(c, ratebuf)) {
1334 for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
1335 if (c->switch_feed_streams[i] >= 0)
1336 do_switch_stream(c, i);
1337 }
1338 }
3120d2a2
PG
1339 }
1340
755bfeab 1341 /* If already streaming this feed, do not let start another feeder. */
d0a5513b
AB
1342 if (stream->feed_opened) {
1343 snprintf(msg, sizeof(msg), "This feed is already being received.");
1344 goto send_error;
1345 }
1346
611c5741 1347 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
6edd6884 1348 current_bandwidth += stream->bandwidth;
115329f1 1349
edfdd798 1350 if (c->post == 0 && max_bandwidth < current_bandwidth) {
42a63c6a
PG
1351 c->http_error = 200;
1352 q = c->buffer;
d445a7e9
PG
1353 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 Server too busy\r\n");
1354 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: text/html\r\n");
1355 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1356 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<html><head><title>Too busy</title></head><body>\r\n");
33f5e2ec 1357 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");
1ad8289e 1358 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<p>The bandwidth being served (including your stream) is %lldkbit/sec, and this exceeds the limit of %lldkbit/sec.</p>\r\n",
6edd6884 1359 current_bandwidth, max_bandwidth);
d445a7e9 1360 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</body></html>\r\n");
42a63c6a
PG
1361
1362 /* prepare output buffer */
1363 c->buffer_ptr = c->buffer;
1364 c->buffer_end = q;
1365 c->state = HTTPSTATE_SEND_HEADER;
1366 return 0;
1367 }
115329f1 1368
829ac53d 1369 if (redir_type != REDIR_NONE) {
7434ba6d 1370 char *hostinfo = 0;
115329f1 1371
7434ba6d
PG
1372 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1373 if (strncasecmp(p, "Host:", 5) == 0) {
1374 hostinfo = p + 5;
1375 break;
1376 }
1377 p = strchr(p, '\n');
1378 if (!p)
1379 break;
1380
1381 p++;
1382 }
1383
1384 if (hostinfo) {
1385 char *eoh;
1386 char hostbuf[260];
1387
1388 while (isspace(*hostinfo))
1389 hostinfo++;
1390
1391 eoh = strchr(hostinfo, '\n');
1392 if (eoh) {
1393 if (eoh[-1] == '\r')
1394 eoh--;
1395
1396 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1397 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1398 hostbuf[eoh - hostinfo] = 0;
1399
1400 c->http_error = 200;
1401 q = c->buffer;
829ac53d
FB
1402 switch(redir_type) {
1403 case REDIR_ASX:
d445a7e9
PG
1404 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASX Follows\r\n");
1405 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
1406 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1407 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ASX Version=\"3\">\r\n");
7c054ea7 1408 //q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<!-- Autogenerated by ffserver -->\r\n");
115329f1 1409 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n",
42a63c6a 1410 hostbuf, filename, info);
d445a7e9 1411 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</ASX>\r\n");
829ac53d
FB
1412 break;
1413 case REDIR_RAM:
d445a7e9
PG
1414 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RAM Follows\r\n");
1415 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: audio/x-pn-realaudio\r\n");
1416 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1417 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "# Autogenerated by ffserver\r\n");
115329f1 1418 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "http://%s/%s%s\r\n",
42a63c6a 1419 hostbuf, filename, info);
829ac53d
FB
1420 break;
1421 case REDIR_ASF:
d445a7e9
PG
1422 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 ASF Redirect follows\r\n");
1423 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: video/x-ms-asf\r\n");
1424 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1425 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "[Reference]\r\n");
115329f1 1426 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Ref1=http://%s/%s%s\r\n",
cde25790 1427 hostbuf, filename, info);
829ac53d
FB
1428 break;
1429 case REDIR_RTSP:
1430 {
1431 char hostname[256], *p;
1432 /* extract only hostname */
f7d78f36 1433 av_strlcpy(hostname, hostbuf, sizeof(hostname));
829ac53d
FB
1434 p = strrchr(hostname, ':');
1435 if (p)
1436 *p = '\0';
d445a7e9 1437 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 RTSP Redirect follows\r\n");
829ac53d 1438 /* XXX: incorrect mime type ? */
d445a7e9
PG
1439 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/x-rtsp\r\n");
1440 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
115329f1
DB
1441 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "rtsp://%s:%d/%s\r\n",
1442 hostname, ntohs(my_rtsp_addr.sin_port),
829ac53d
FB
1443 filename);
1444 }
1445 break;
1446 case REDIR_SDP:
1447 {
0c1a9eda 1448 uint8_t *sdp_data;
829ac53d
FB
1449 int sdp_data_size, len;
1450 struct sockaddr_in my_addr;
1451
d445a7e9
PG
1452 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1453 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: application/sdp\r\n");
1454 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
829ac53d
FB
1455
1456 len = sizeof(my_addr);
1457 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
115329f1 1458
829ac53d 1459 /* XXX: should use a dynamic buffer */
115329f1
DB
1460 sdp_data_size = prepare_sdp_description(stream,
1461 &sdp_data,
829ac53d
FB
1462 my_addr.sin_addr);
1463 if (sdp_data_size > 0) {
1464 memcpy(q, sdp_data, sdp_data_size);
1465 q += sdp_data_size;
1466 *q = '\0';
1467 av_free(sdp_data);
1468 }
1469 }
1470 break;
1471 default:
0f4e8165 1472 abort();
829ac53d 1473 break;
2effd274 1474 }
7434ba6d
PG
1475
1476 /* prepare output buffer */
1477 c->buffer_ptr = c->buffer;
1478 c->buffer_end = q;
1479 c->state = HTTPSTATE_SEND_HEADER;
1480 return 0;
1481 }
1482 }
1483 }
1484
d445a7e9 1485 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
7434ba6d 1486 goto send_error;
85f07f22
FB
1487 }
1488
a6e14edd 1489 stream->conns_served++;
7434ba6d 1490
85f07f22
FB
1491 /* XXX: add there authenticate and IP match */
1492
edfdd798 1493 if (c->post) {
85f07f22
FB
1494 /* if post, it means a feed is being sent */
1495 if (!stream->is_feed) {
7434ba6d
PG
1496 /* However it might be a status report from WMP! Lets log the data
1497 * as it might come in handy one day
1498 */
1499 char *logline = 0;
3120d2a2 1500 int client_id = 0;
115329f1 1501
7434ba6d
PG
1502 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1503 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1504 logline = p;
1505 break;
1506 }
611c5741 1507 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
3120d2a2 1508 client_id = strtol(p + 18, 0, 10);
7434ba6d
PG
1509 p = strchr(p, '\n');
1510 if (!p)
1511 break;
1512
1513 p++;
1514 }
1515
1516 if (logline) {
1517 char *eol = strchr(logline, '\n');
1518
1519 logline += 17;
1520
1521 if (eol) {
1522 if (eol[-1] == '\r')
1523 eol--;
7906085f 1524 http_log("%.*s\n", (int) (eol - logline), logline);
7434ba6d
PG
1525 c->suppress_log = 1;
1526 }
1527 }
3120d2a2 1528
cde25790
PG
1529#ifdef DEBUG_WMP
1530 http_log("\nGot request:\n%s\n", c->buffer);
3120d2a2
PG
1531#endif
1532
1533 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1534 HTTPContext *wmpc;
1535
1536 /* Now we have to find the client_id */
1537 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1538 if (wmpc->wmp_client_id == client_id)
1539 break;
1540 }
1541
2d563d2f
AB
1542 if (wmpc && modify_current_stream(wmpc, ratebuf))
1543 wmpc->switch_pending = 1;
3120d2a2 1544 }
115329f1 1545
d445a7e9 1546 snprintf(msg, sizeof(msg), "POST command not handled");
cb275dd9 1547 c->stream = 0;
85f07f22
FB
1548 goto send_error;
1549 }
1550 if (http_start_receive_data(c) < 0) {
d445a7e9 1551 snprintf(msg, sizeof(msg), "could not open feed");
85f07f22
FB
1552 goto send_error;
1553 }
1554 c->http_error = 0;
1555 c->state = HTTPSTATE_RECEIVE_DATA;
1556 return 0;
1557 }
1558
cde25790 1559#ifdef DEBUG_WMP
611c5741 1560 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
cde25790 1561 http_log("\nGot request:\n%s\n", c->buffer);
3120d2a2
PG
1562#endif
1563
85f07f22 1564 if (c->stream->stream_type == STREAM_TYPE_STATUS)
dca21085 1565 goto send_status;
85f07f22
FB
1566
1567 /* open input stream */
1568 if (open_input_stream(c, info) < 0) {
d445a7e9 1569 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
85f07f22
FB
1570 goto send_error;
1571 }
1572
1573 /* prepare http header */
1574 q = c->buffer;
d445a7e9 1575 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
85f07f22
FB
1576 mime_type = c->stream->fmt->mime_type;
1577 if (!mime_type)
087fa475 1578 mime_type = "application/x-octet-stream";
d445a7e9 1579 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
85f07f22
FB
1580
1581 /* for asf, we need extra headers */
8256c0a3 1582 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
3120d2a2 1583 /* Need to allocate a client id */
3120d2a2 1584
1df93ae9 1585 c->wmp_client_id = av_random(&random_state) & 0x7fffffff;
3120d2a2 1586
d445a7e9 1587 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);
85f07f22 1588 }
d445a7e9
PG
1589 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1590 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
115329f1 1591
85f07f22
FB
1592 /* prepare output buffer */
1593 c->http_error = 0;
1594 c->buffer_ptr = c->buffer;
1595 c->buffer_end = q;
1596 c->state = HTTPSTATE_SEND_HEADER;
1597 return 0;
1598 send_error:
1599 c->http_error = 404;
1600 q = c->buffer;
d445a7e9
PG
1601 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 404 Not Found\r\n");
1602 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-type: %s\r\n", "text/html");
1603 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1604 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HTML>\n");
1605 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
1606 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "<BODY>%s</BODY>\n", msg);
1607 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "</HTML>\n");
85f07f22
FB
1608
1609 /* prepare output buffer */
1610 c->buffer_ptr = c->buffer;
1611 c->buffer_end = q;
1612 c->state = HTTPSTATE_SEND_HEADER;
1613 return 0;
dca21085
SS
1614 send_status:
1615 compute_status(c);
85f07f22
FB
1616 c->http_error = 200; /* horrible : we use this value to avoid
1617 going to the send data state */
1618 c->state = HTTPSTATE_SEND_HEADER;
1619 return 0;
1620}
1621
0c1a9eda 1622static void fmt_bytecount(ByteIOContext *pb, int64_t count)
2ac887ba
PG
1623{
1624 static const char *suffix = " kMGTP";
1625 const char *s;
1626
611c5741 1627 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
2ac887ba 1628
4733abcb 1629 url_fprintf(pb, "%"PRId64"%c", count, *s);
2ac887ba
PG
1630}
1631
dca21085 1632static void compute_status(HTTPContext *c)
85f07f22
FB
1633{
1634 HTTPContext *c1;
1635 FFStream *stream;
2effd274 1636 char *p;
85f07f22 1637 time_t ti;
2effd274 1638 int i, len;
899681cd 1639 ByteIOContext *pb;
cde25790 1640
899681cd 1641 if (url_open_dyn_buf(&pb) < 0) {
2effd274 1642 /* XXX: return an error ? */
cde25790 1643 c->buffer_ptr = c->buffer;
2effd274
FB
1644 c->buffer_end = c->buffer;
1645 return;
cde25790 1646 }
85f07f22 1647
2effd274
FB
1648 url_fprintf(pb, "HTTP/1.0 200 OK\r\n");
1649 url_fprintf(pb, "Content-type: %s\r\n", "text/html");
1650 url_fprintf(pb, "Pragma: no-cache\r\n");
1651 url_fprintf(pb, "\r\n");
115329f1 1652
17b01199 1653 url_fprintf(pb, "<HEAD><TITLE>%s Status</TITLE>\n", program_name);
0679719d 1654 if (c->stream->feed_filename[0])
2effd274 1655 url_fprintf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
2effd274 1656 url_fprintf(pb, "</HEAD>\n<BODY>");
17b01199 1657 url_fprintf(pb, "<H1>%s Status</H1>\n", program_name);
85f07f22 1658 /* format status */
2effd274
FB
1659 url_fprintf(pb, "<H2>Available Streams</H2>\n");
1660 url_fprintf(pb, "<TABLE cellspacing=0 cellpadding=4>\n");
1661 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");
85f07f22
FB
1662 stream = first_stream;
1663 while (stream != NULL) {
42a63c6a
PG
1664 char sfilename[1024];
1665 char *eosf;
1666
a6e14edd 1667 if (stream->feed != stream) {
f7d78f36 1668 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
a6e14edd
PG
1669 eosf = sfilename + strlen(sfilename);
1670 if (eosf - sfilename >= 4) {
611c5741 1671 if (strcmp(eosf - 4, ".asf") == 0)
a6e14edd 1672 strcpy(eosf - 4, ".asx");
611c5741 1673 else if (strcmp(eosf - 3, ".rm") == 0)
a6e14edd 1674 strcpy(eosf - 3, ".ram");
25e3e53d 1675 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
829ac53d
FB
1676 /* generate a sample RTSP director if
1677 unicast. Generate an SDP redirector if
1678 multicast */
2effd274
FB
1679 eosf = strrchr(sfilename, '.');
1680 if (!eosf)
1681 eosf = sfilename + strlen(sfilename);
829ac53d
FB
1682 if (stream->is_multicast)
1683 strcpy(eosf, ".sdp");
1684 else
1685 strcpy(eosf, ".rtsp");
a6e14edd 1686 }
42a63c6a 1687 }
115329f1
DB
1688
1689 url_fprintf(pb, "<TR><TD><A HREF=\"/%s\">%s</A> ",
a6e14edd 1690 sfilename, stream->filename);
2effd274 1691 url_fprintf(pb, "<td align=right> %d <td align=right> ",
2ac887ba 1692 stream->conns_served);
2effd274 1693 fmt_bytecount(pb, stream->bytes_served);
a6e14edd 1694 switch(stream->stream_type) {
ace21da3 1695 case STREAM_TYPE_LIVE: {
a6e14edd
PG
1696 int audio_bit_rate = 0;
1697 int video_bit_rate = 0;
58445440
ZK
1698 const char *audio_codec_name = "";
1699 const char *video_codec_name = "";
1700 const char *audio_codec_name_extra = "";
1701 const char *video_codec_name_extra = "";
a6e14edd
PG
1702
1703 for(i=0;i<stream->nb_streams;i++) {
1704 AVStream *st = stream->streams[i];
01f4895c
MN
1705 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1706 switch(st->codec->codec_type) {
a6e14edd 1707 case CODEC_TYPE_AUDIO:
01f4895c 1708 audio_bit_rate += st->codec->bit_rate;
a6e14edd
PG
1709 if (codec) {
1710 if (*audio_codec_name)
1711 audio_codec_name_extra = "...";
1712 audio_codec_name = codec->name;
1713 }
1714 break;
1715 case CODEC_TYPE_VIDEO:
01f4895c 1716 video_bit_rate += st->codec->bit_rate;
a6e14edd
PG
1717 if (codec) {
1718 if (*video_codec_name)
1719 video_codec_name_extra = "...";
1720 video_codec_name = codec->name;
1721 }
1722 break;
e240a0bb 1723 case CODEC_TYPE_DATA:
01f4895c 1724 video_bit_rate += st->codec->bit_rate;
e240a0bb 1725 break;
a6e14edd 1726 default:
0f4e8165 1727 abort();
79c4ea3c 1728 }
85f07f22 1729 }
115329f1 1730 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",
a6e14edd 1731 stream->fmt->name,
6edd6884 1732 stream->bandwidth,
a6e14edd
PG
1733 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1734 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
611c5741 1735 if (stream->feed)
2effd274 1736 url_fprintf(pb, "<TD>%s", stream->feed->filename);
611c5741 1737 else
2effd274 1738 url_fprintf(pb, "<TD>%s", stream->feed_filename);
2effd274 1739 url_fprintf(pb, "\n");
85f07f22 1740 }
a6e14edd
PG
1741 break;
1742 default:
2effd274 1743 url_fprintf(pb, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
a6e14edd 1744 break;
85f07f22 1745 }
85f07f22
FB
1746 }
1747 stream = stream->next;
1748 }
2effd274 1749 url_fprintf(pb, "</TABLE>\n");
a6e14edd
PG
1750
1751 stream = first_stream;
1752 while (stream != NULL) {
1753 if (stream->feed == stream) {
2effd274 1754 url_fprintf(pb, "<h2>Feed %s</h2>", stream->filename);
cde25790 1755 if (stream->pid) {
2effd274 1756 url_fprintf(pb, "Running as pid %d.\n", stream->pid);
cde25790 1757
2effd274
FB
1758#if defined(linux) && !defined(CONFIG_NOCUTILS)
1759 {
1760 FILE *pid_stat;
1761 char ps_cmd[64];
1762
1763 /* This is somewhat linux specific I guess */
115329f1
DB
1764 snprintf(ps_cmd, sizeof(ps_cmd),
1765 "ps -o \"%%cpu,cputime\" --no-headers %d",
2effd274 1766 stream->pid);
115329f1 1767
2effd274
FB
1768 pid_stat = popen(ps_cmd, "r");
1769 if (pid_stat) {
1770 char cpuperc[10];
1771 char cpuused[64];
115329f1
DB
1772
1773 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2effd274
FB
1774 cpuused) == 2) {
1775 url_fprintf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1776 cpuperc, cpuused);
1777 }
1778 fclose(pid_stat);
cde25790 1779 }
cde25790
PG
1780 }
1781#endif
1782
2effd274 1783 url_fprintf(pb, "<p>");
cde25790 1784 }
2effd274 1785 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");
a6e14edd
PG
1786
1787 for (i = 0; i < stream->nb_streams; i++) {
1788 AVStream *st = stream->streams[i];
01f4895c 1789 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
b29f97d1 1790 const char *type = "unknown";
b582f314
PG
1791 char parameters[64];
1792
1793 parameters[0] = 0;
a6e14edd 1794
01f4895c 1795 switch(st->codec->codec_type) {
a6e14edd
PG
1796 case CODEC_TYPE_AUDIO:
1797 type = "audio";
acdc8520 1798 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
a6e14edd
PG
1799 break;
1800 case CODEC_TYPE_VIDEO:
1801 type = "video";
01f4895c
MN
1802 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1803 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
a6e14edd
PG
1804 break;
1805 default:
0f4e8165 1806 abort();
a6e14edd 1807 }
2effd274 1808 url_fprintf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
01f4895c 1809 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
a6e14edd 1810 }
2effd274 1811 url_fprintf(pb, "</table>\n");
a6e14edd 1812
115329f1 1813 }
a6e14edd
PG
1814 stream = stream->next;
1815 }
115329f1 1816
85f07f22
FB
1817#if 0
1818 {
1819 float avg;
1820 AVCodecContext *enc;
1821 char buf[1024];
115329f1 1822
85f07f22
FB
1823 /* feed status */
1824 stream = first_feed;
1825 while (stream != NULL) {
2effd274
FB
1826 url_fprintf(pb, "<H1>Feed '%s'</H1>\n", stream->filename);
1827 url_fprintf(pb, "<TABLE>\n");
1828 url_fprintf(pb, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
85f07f22
FB
1829 for(i=0;i<stream->nb_streams;i++) {
1830 AVStream *st = stream->streams[i];
1831 FeedData *fdata = st->priv_data;
01f4895c 1832 enc = st->codec;
115329f1 1833
85f07f22
FB
1834 avcodec_string(buf, sizeof(buf), enc);
1835 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
1836 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
1837 avg /= enc->frame_size;
949b1a13 1838 url_fprintf(pb, "<TR><TD>%s <TD> %d <TD> %"PRId64" <TD> %0.1f\n",
85f07f22
FB
1839 buf, enc->frame_number, fdata->data_count, avg / 1000.0);
1840 }
2effd274 1841 url_fprintf(pb, "</TABLE>\n");
85f07f22
FB
1842 stream = stream->next_feed;
1843 }
1844 }
1845#endif
1846
1847 /* connection status */
2effd274 1848 url_fprintf(pb, "<H2>Connection Status</H2>\n");
85f07f22 1849
2effd274 1850 url_fprintf(pb, "Number of connections: %d / %d<BR>\n",
85f07f22
FB
1851 nb_connections, nb_max_connections);
1852
1ad8289e 1853 url_fprintf(pb, "Bandwidth in use: %lldk / %lldk<BR>\n",
6edd6884 1854 current_bandwidth, max_bandwidth);
42a63c6a 1855
2effd274
FB
1856 url_fprintf(pb, "<TABLE>\n");
1857 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");
85f07f22
FB
1858 c1 = first_http_ctx;
1859 i = 0;
2effd274 1860 while (c1 != NULL) {
cde25790
PG
1861 int bitrate;
1862 int j;
1863
1864 bitrate = 0;
2effd274
FB
1865 if (c1->stream) {
1866 for (j = 0; j < c1->stream->nb_streams; j++) {
2d563d2f 1867 if (!c1->stream->feed)
01f4895c 1868 bitrate += c1->stream->streams[j]->codec->bit_rate;
2d563d2f
AB
1869 else if (c1->feed_streams[j] >= 0)
1870 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
cde25790
PG
1871 }
1872 }
1873
85f07f22
FB
1874 i++;
1875 p = inet_ntoa(c1->from_addr.sin_addr);
115329f1
DB
1876 url_fprintf(pb, "<TR><TD><B>%d</B><TD>%s%s<TD>%s<TD>%s<TD>%s<td align=right>",
1877 i,
1878 c1->stream ? c1->stream->filename : "",
2effd274 1879 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
115329f1 1880 p,
2effd274
FB
1881 c1->protocol,
1882 http_state[c1->state]);
1883 fmt_bytecount(pb, bitrate);
1884 url_fprintf(pb, "<td align=right>");
1885 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1886 url_fprintf(pb, "<td align=right>");
1887 fmt_bytecount(pb, c1->data_count);
1888 url_fprintf(pb, "\n");
85f07f22
FB
1889 c1 = c1->next;
1890 }
2effd274 1891 url_fprintf(pb, "</TABLE>\n");
115329f1 1892
85f07f22
FB
1893 /* date */
1894 ti = time(NULL);
1895 p = ctime(&ti);
2effd274
FB
1896 url_fprintf(pb, "<HR size=1 noshade>Generated at %s", p);
1897 url_fprintf(pb, "</BODY>\n</HTML>\n");
85f07f22 1898
2effd274
FB
1899 len = url_close_dyn_buf(pb, &c->pb_buffer);
1900 c->buffer_ptr = c->pb_buffer;
1901 c->buffer_end = c->pb_buffer + len;
85f07f22
FB
1902}
1903
2effd274
FB
1904/* check if the parser needs to be opened for stream i */
1905static void open_parser(AVFormatContext *s, int i)
85f07f22 1906{
2effd274
FB
1907 AVStream *st = s->streams[i];
1908 AVCodec *codec;
31def229 1909
01f4895c
MN
1910 if (!st->codec->codec) {
1911 codec = avcodec_find_decoder(st->codec->codec_id);
2effd274 1912 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
01f4895c 1913 st->codec->parse_only = 1;
611c5741 1914 if (avcodec_open(st->codec, codec) < 0)
01f4895c 1915 st->codec->parse_only = 0;
cde25790
PG
1916 }
1917 }
85f07f22
FB
1918}
1919
1920static int open_input_stream(HTTPContext *c, const char *info)
1921{
1922 char buf[128];
1923 char input_filename[1024];
1924 AVFormatContext *s;
c351cc7f 1925 int buf_size, i, ret;
0c1a9eda 1926 int64_t stream_pos;
85f07f22
FB
1927
1928 /* find file name */
1929 if (c->stream->feed) {
1930 strcpy(input_filename, c->stream->feed->feed_filename);
1931 buf_size = FFM_PACKET_SIZE;
1932 /* compute position (absolute time) */
ace21da3 1933 if (find_info_tag(buf, sizeof(buf), "date", info)) {
85f07f22 1934 stream_pos = parse_date(buf, 0);
f9436161
SS
1935 if (stream_pos == INT64_MIN)
1936 return -1;
ace21da3 1937 } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
f747e6d3 1938 int prebuffer = strtol(buf, 0, 10);
0c1a9eda 1939 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
611c5741 1940 } else
0c1a9eda 1941 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
85f07f22
FB
1942 } else {
1943 strcpy(input_filename, c->stream->feed_filename);
1944 buf_size = 0;
1945 /* compute position (relative time) */
ace21da3 1946 if (find_info_tag(buf, sizeof(buf), "date", info)) {
85f07f22 1947 stream_pos = parse_date(buf, 1);
f9436161
SS
1948 if (stream_pos == INT64_MIN)
1949 return -1;
ace21da3 1950 } else
85f07f22 1951 stream_pos = 0;
85f07f22
FB
1952 }
1953 if (input_filename[0] == '\0')
1954 return -1;
1955
8256c0a3
PG
1956#if 0
1957 { time_t when = stream_pos / 1000000;
949b1a13 1958 http_log("Stream pos = %"PRId64", time=%s", stream_pos, ctime(&when));
8256c0a3
PG
1959 }
1960#endif
1961
85f07f22 1962 /* open stream */
c351cc7f
BC
1963 if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
1964 buf_size, c->stream->ap_in)) < 0) {
1965 http_log("could not open %s: %d\n", input_filename, ret);
85f07f22 1966 return -1;
2effd274 1967 }
9dc0bc3d 1968 s->flags |= AVFMT_FLAG_GENPTS;
85f07f22 1969 c->fmt_in = s;
89da5781 1970 av_find_stream_info(c->fmt_in);
115329f1 1971
2effd274
FB
1972 /* open each parser */
1973 for(i=0;i<s->nb_streams;i++)
1974 open_parser(s, i);
1975
1976 /* choose stream as clock source (we favorize video stream if
1977 present) for packet sending */
1978 c->pts_stream_index = 0;
1979 for(i=0;i<c->stream->nb_streams;i++) {
115329f1 1980 if (c->pts_stream_index == 0 &&
01f4895c 1981 c->stream->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
2effd274
FB
1982 c->pts_stream_index = i;
1983 }
1984 }
85f07f22 1985
e8d27bc3 1986#if 1
611c5741 1987 if (c->fmt_in->iformat->read_seek)
60a04f7f 1988 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
e240a0bb 1989#endif
2effd274
FB
1990 /* set the start time (needed for maxtime and RTP packet timing) */
1991 c->start_time = cur_time;
1992 c->first_pts = AV_NOPTS_VALUE;
85f07f22
FB
1993 return 0;
1994}
1995
e240a0bb
FB
1996/* return the server clock (in us) */
1997static int64_t get_server_clock(HTTPContext *c)
2effd274 1998{
e240a0bb 1999 /* compute current pts value from system time */
c3f58185 2000 return (cur_time - c->start_time) * 1000;
2effd274
FB
2001}
2002
e240a0bb
FB
2003/* return the estimated time at which the current packet must be sent
2004 (in us) */
2005static int64_t get_packet_send_clock(HTTPContext *c)
2effd274 2006{
e240a0bb 2007 int bytes_left, bytes_sent, frame_bytes;
115329f1 2008
e240a0bb 2009 frame_bytes = c->cur_frame_bytes;
611c5741 2010 if (frame_bytes <= 0)
e240a0bb 2011 return c->cur_pts;
611c5741 2012 else {
e240a0bb
FB
2013 bytes_left = c->buffer_end - c->buffer_ptr;
2014 bytes_sent = frame_bytes - bytes_left;
2015 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2effd274 2016 }
2effd274 2017}
2effd274 2018
2effd274 2019
2effd274
FB
2020static int http_prepare_data(HTTPContext *c)
2021{
2022 int i, len, ret;
2023 AVFormatContext *ctx;
2024
bc351386 2025 av_freep(&c->pb_buffer);
2effd274
FB
2026 switch(c->state) {
2027 case HTTPSTATE_SEND_DATA_HEADER:
2028 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
f7d78f36
MR
2029 av_strlcpy(c->fmt_ctx.author, c->stream->author,
2030 sizeof(c->fmt_ctx.author));
2031 av_strlcpy(c->fmt_ctx.comment, c->stream->comment,
2032 sizeof(c->fmt_ctx.comment));
2033 av_strlcpy(c->fmt_ctx.copyright, c->stream->copyright,
2034 sizeof(c->fmt_ctx.copyright));
2035 av_strlcpy(c->fmt_ctx.title, c->stream->title,
2036 sizeof(c->fmt_ctx.title));
2effd274 2037
3d9cc27d 2038 for(i=0;i<c->stream->nb_streams;i++) {
2effd274 2039 AVStream *st;
bb270c08 2040 AVStream *src;
2effd274
FB
2041 st = av_mallocz(sizeof(AVStream));
2042 c->fmt_ctx.streams[i] = st;
2043 /* if file or feed, then just take streams from FFStream struct */
115329f1 2044 if (!c->stream->feed ||
2effd274 2045 c->stream->feed == c->stream)
7c054ea7 2046 src = c->stream->streams[i];
2effd274 2047 else
7c054ea7
PG
2048 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2049
bb270c08
DB
2050 *st = *src;
2051 st->priv_data = 0;
01f4895c 2052 st->codec->frame_number = 0; /* XXX: should be done in
2effd274
FB
2053 AVStream, not in codec */
2054 }
3d9cc27d
BC
2055 /* set output format parameters */
2056 c->fmt_ctx.oformat = c->stream->fmt;
2057 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2058
2effd274
FB
2059 c->got_key_frame = 0;
2060
2061 /* prepare header and save header data in a stream */
2062 if (url_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2063 /* XXX: potential leak */
2064 return -1;
2065 }
899681cd 2066 c->fmt_ctx.pb->is_streamed = 1;
2effd274 2067
8aae202e
BC
2068 /*
2069 * HACK to avoid mpeg ps muxer to spit many underflow errors
2070 * Default value from FFmpeg
2071 * Try to set it use configuration option
2072 */
2073 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2074 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2075
3c27199b 2076 av_set_parameters(&c->fmt_ctx, NULL);
929a9b75
BC
2077 if (av_write_header(&c->fmt_ctx) < 0) {
2078 http_log("Error writing output header\n");
f75cdda7 2079 return -1;
929a9b75 2080 }
2effd274 2081
899681cd 2082 len = url_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2effd274
FB
2083 c->buffer_ptr = c->pb_buffer;
2084 c->buffer_end = c->pb_buffer + len;
2085
2086 c->state = HTTPSTATE_SEND_DATA;
85f07f22
FB
2087 c->last_packet_sent = 0;
2088 break;
2089 case HTTPSTATE_SEND_DATA:
2090 /* find a new packet */
3b371676
BC
2091 /* read a packet from the input stream */
2092 if (c->stream->feed)
2093 ffm_set_write_index(c->fmt_in,
2094 c->stream->feed->feed_write_index,
2095 c->stream->feed->feed_size);
2096
2097 if (c->stream->max_time &&
2098 c->stream->max_time + c->start_time - cur_time < 0)
2099 /* We have timed out */
2100 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2101 else {
2102 AVPacket pkt;
2103 redo:
2104 if (av_read_frame(c->fmt_in, &pkt) < 0) {
2105 if (c->stream->feed && c->stream->feed->feed_opened) {
2106 /* if coming from feed, it means we reached the end of the
2107 ffm file, so must wait for more data */
2108 c->state = HTTPSTATE_WAIT_FEED;
2109 return 1; /* state changed */
2effd274 2110 } else {
3b371676
BC
2111 if (c->stream->loop) {
2112 av_close_input_file(c->fmt_in);
2113 c->fmt_in = NULL;
2114 if (open_input_stream(c, "") < 0)
2115 goto no_loop;
2116 goto redo;
2117 } else {
2118 no_loop:
2119 /* must send trailer now because eof or error */
2120 c->state = HTTPSTATE_SEND_DATA_TRAILER;
1bc1cfdd 2121 }
3b371676
BC
2122 }
2123 } else {
084a8912 2124 int source_index = pkt.stream_index;
3b371676
BC
2125 /* update first pts if needed */
2126 if (c->first_pts == AV_NOPTS_VALUE) {
2127 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2128 c->start_time = cur_time;
2129 }
2130 /* send it to the appropriate stream */
2131 if (c->stream->feed) {
2132 /* if coming from a feed, select the right stream */
2133 if (c->switch_pending) {
2134 c->switch_pending = 0;
cde25790 2135 for(i=0;i<c->stream->nb_streams;i++) {
3b371676 2136 if (c->switch_feed_streams[i] == pkt.stream_index)
611c5741 2137 if (pkt.flags & PKT_FLAG_KEY)
3b371676
BC
2138 do_switch_stream(c, i);
2139 if (c->switch_feed_streams[i] >= 0)
2140 c->switch_pending = 1;
cde25790 2141 }
3b371676
BC
2142 }
2143 for(i=0;i<c->stream->nb_streams;i++) {
2144 if (c->feed_streams[i] == pkt.stream_index) {
78728064 2145 AVStream *st = c->fmt_in->streams[source_index];
3b371676 2146 pkt.stream_index = i;
180b7026
BC
2147 if (pkt.flags & PKT_FLAG_KEY &&
2148 (st->codec->codec_type == CODEC_TYPE_VIDEO ||
2149 c->stream->nb_streams == 1))
0332f549
BC
2150 c->got_key_frame = 1;
2151 if (!c->stream->send_on_key || c->got_key_frame)
3b371676
BC
2152 goto send_it;
2153 }
2154 }
2155 } else {
2156 AVCodecContext *codec;
dc3a6a36
BC
2157 AVStream *ist, *ost;
2158 send_it:
2159 ist = c->fmt_in->streams[source_index];
3b371676
BC
2160 /* specific handling for RTP: we use several
2161 output stream (one for each RTP
2162 connection). XXX: need more abstract handling */
2163 if (c->is_packetized) {
3b371676 2164 /* compute send time and duration */
8f56ccca
BC
2165 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2166 if (ist->start_time != AV_NOPTS_VALUE)
2167 c->cur_pts -= av_rescale_q(ist->start_time, ist->time_base, AV_TIME_BASE_Q);
2168 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
e240a0bb 2169#if 0
3b371676
BC
2170 printf("index=%d pts=%0.3f duration=%0.6f\n",
2171 pkt.stream_index,
2172 (double)c->cur_pts /
2173 AV_TIME_BASE,
2174 (double)c->cur_frame_duration /
2175 AV_TIME_BASE);
e240a0bb 2176#endif
3b371676
BC
2177 /* find RTP context */
2178 c->packet_stream_index = pkt.stream_index;
2179 ctx = c->rtp_ctx[c->packet_stream_index];
2180 if(!ctx) {
8a0b55ff 2181 av_free_packet(&pkt);
3b371676 2182 break;
8a0b55ff 2183 }
3b371676
BC
2184 codec = ctx->streams[0]->codec;
2185 /* only one stream per RTP connection */
2186 pkt.stream_index = 0;
2187 } else {
2188 ctx = &c->fmt_ctx;
2189 /* Fudge here */
3ab29d8e 2190 codec = ctx->streams[pkt.stream_index]->codec;
3b371676
BC
2191 }
2192
2193 if (c->is_packetized) {
2194 int max_packet_size;
2195 if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP)
2196 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2197 else
2198 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2199 ret = url_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2200 } else {
2201 ret = url_open_dyn_buf(&ctx->pb);
2202 }
2203 if (ret < 0) {
2204 /* XXX: potential leak */
2205 return -1;
2206 }
3ab29d8e
BC
2207 ost = ctx->streams[pkt.stream_index];
2208
b0675954 2209 ctx->pb->is_streamed = 1;
3b371676 2210 if (pkt.dts != AV_NOPTS_VALUE)
d80904cc 2211 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
3b371676 2212 if (pkt.pts != AV_NOPTS_VALUE)
d80904cc
BC
2213 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2214 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
3766ed72
BC
2215 if (av_write_frame(ctx, &pkt) < 0) {
2216 http_log("Error writing frame to output\n");
3b371676 2217 c->state = HTTPSTATE_SEND_DATA_TRAILER;
3766ed72 2218 }
3b371676
BC
2219
2220 len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2221 c->cur_frame_bytes = len;
2222 c->buffer_ptr = c->pb_buffer;
2223 c->buffer_end = c->pb_buffer + len;
2224
2225 codec->frame_number++;
2226 if (len == 0) {
2227 av_free_packet(&pkt);
2228 goto redo;
f747e6d3 2229 }
85f07f22 2230 }
3b371676 2231 av_free_packet(&pkt);
85f07f22 2232 }
3b371676 2233 }
85f07f22
FB
2234 break;
2235 default:
2236 case HTTPSTATE_SEND_DATA_TRAILER:
2237 /* last packet test ? */
2effd274 2238 if (c->last_packet_sent || c->is_packetized)
85f07f22 2239 return -1;
2effd274 2240 ctx = &c->fmt_ctx;
85f07f22 2241 /* prepare header */
2effd274
FB
2242 if (url_open_dyn_buf(&ctx->pb) < 0) {
2243 /* XXX: potential leak */
2244 return -1;
2245 }
58bd615f 2246 c->fmt_ctx.pb->is_streamed = 1;
2effd274 2247 av_write_trailer(ctx);
899681cd 2248 len = url_close_dyn_buf(ctx->pb, &c->pb_buffer);
2effd274
FB
2249 c->buffer_ptr = c->pb_buffer;
2250 c->buffer_end = c->pb_buffer + len;
2251
85f07f22
FB
2252 c->last_packet_sent = 1;
2253 break;
2254 }
2255 return 0;
2256}
2257
2258/* should convert the format at the same time */
bc351386
FB
2259/* send data starting at c->buffer_ptr to the output connection
2260 (either UDP or TCP connection) */
5eb765ef 2261static int http_send_data(HTTPContext *c)
85f07f22 2262{
e240a0bb 2263 int len, ret;
85f07f22 2264
bc351386
FB
2265 for(;;) {
2266 if (c->buffer_ptr >= c->buffer_end) {
2267 ret = http_prepare_data(c);
2268 if (ret < 0)
2269 return -1;
611c5741 2270 else if (ret != 0)
bc351386
FB
2271 /* state change requested */
2272 break;
2effd274 2273 } else {
bc351386
FB
2274 if (c->is_packetized) {
2275 /* RTP data output */
2276 len = c->buffer_end - c->buffer_ptr;
2277 if (len < 4) {
2278 /* fail safe - should never happen */
2279 fail1:
2280 c->buffer_ptr = c->buffer_end;
2effd274
FB
2281 return 0;
2282 }
bc351386
FB
2283 len = (c->buffer_ptr[0] << 24) |
2284 (c->buffer_ptr[1] << 16) |
2285 (c->buffer_ptr[2] << 8) |
2286 (c->buffer_ptr[3]);
2287 if (len > (c->buffer_end - c->buffer_ptr))
2288 goto fail1;
e240a0bb
FB
2289 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2290 /* nothing to send yet: we can wait */
2291 return 0;
2292 }
2293
2294 c->data_count += len;
2295 update_datarate(&c->datarate, c->data_count);
2296 if (c->stream)
2297 c->stream->bytes_served += len;
2298
bc351386
FB
2299 if (c->rtp_protocol == RTSP_PROTOCOL_RTP_TCP) {
2300 /* RTP packets are sent inside the RTSP TCP connection */
899681cd 2301 ByteIOContext *pb;
bc351386
FB
2302 int interleaved_index, size;
2303 uint8_t header[4];
2304 HTTPContext *rtsp_c;
115329f1 2305
bc351386
FB
2306 rtsp_c = c->rtsp_c;
2307 /* if no RTSP connection left, error */
2308 if (!rtsp_c)
2309 return -1;
2310 /* if already sending something, then wait. */
611c5741 2311 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
bc351386 2312 break;
899681cd 2313 if (url_open_dyn_buf(&pb) < 0)
bc351386
FB
2314 goto fail1;
2315 interleaved_index = c->packet_stream_index * 2;
2316 /* RTCP packets are sent at odd indexes */
2317 if (c->buffer_ptr[1] == 200)
2318 interleaved_index++;
2319 /* write RTSP TCP header */
2320 header[0] = '$';
2321 header[1] = interleaved_index;
2322 header[2] = len >> 8;
2323 header[3] = len;
2324 put_buffer(pb, header, 4);
2325 /* write RTP packet data */
2326 c->buffer_ptr += 4;
2327 put_buffer(pb, c->buffer_ptr, len);
2328 size = url_close_dyn_buf(pb, &c->packet_buffer);
2329 /* prepare asynchronous TCP sending */
2330 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2331 rtsp_c->packet_buffer_end = c->packet_buffer + size;
e240a0bb 2332 c->buffer_ptr += len;
115329f1 2333
e240a0bb 2334 /* send everything we can NOW */
c60202df
AB
2335 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2336 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
611c5741 2337 if (len > 0)
e240a0bb 2338 rtsp_c->packet_buffer_ptr += len;
e240a0bb
FB
2339 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2340 /* if we could not send all the data, we will
2341 send it later, so a new state is needed to
2342 "lock" the RTSP TCP connection */
2343 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2344 break;
611c5741 2345 } else
e240a0bb
FB
2346 /* all data has been sent */
2347 av_freep(&c->packet_buffer);
e240a0bb
FB
2348 } else {
2349 /* send RTP packet directly in UDP */
bc351386 2350 c->buffer_ptr += 4;
115329f1 2351 url_write(c->rtp_handles[c->packet_stream_index],
bc351386 2352 c->buffer_ptr, len);
e240a0bb
FB
2353 c->buffer_ptr += len;
2354 /* here we continue as we can send several packets per 10 ms slot */
bc351386 2355 }
bc351386
FB
2356 } else {
2357 /* TCP data output */
c60202df 2358 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
bc351386 2359 if (len < 0) {
8da4034f 2360 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
611c5741 2361 ff_neterrno() != FF_NETERROR(EINTR))
bc351386
FB
2362 /* error : close connection */
2363 return -1;
611c5741 2364 else
bc351386 2365 return 0;
611c5741 2366 } else
bc351386 2367 c->buffer_ptr += len;
611c5741 2368
e240a0bb
FB
2369 c->data_count += len;
2370 update_datarate(&c->datarate, c->data_count);
2371 if (c->stream)
2372 c->stream->bytes_served += len;
2373 break;
2effd274 2374 }
85f07f22 2375 }
bc351386 2376 } /* for(;;) */
85f07f22
FB
2377 return 0;
2378}
2379
2380static int http_start_receive_data(HTTPContext *c)
2381{
2382 int fd;
2383
2384 if (c->stream->feed_opened)
2385 return -1;
2386
e322ea48
PG
2387 /* Don't permit writing to this one */
2388 if (c->stream->readonly)
2389 return -1;
2390
85f07f22
FB
2391 /* open feed */
2392 fd = open(c->stream->feed_filename, O_RDWR);
929a9b75
BC
2393 if (fd < 0) {
2394 http_log("Error opening feeder file: %s\n", strerror(errno));
85f07f22 2395 return -1;
929a9b75 2396 }
85f07f22 2397 c->feed_fd = fd;
115329f1 2398
85f07f22
FB
2399 c->stream->feed_write_index = ffm_read_write_index(fd);
2400 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2401 lseek(fd, 0, SEEK_SET);
2402
2403 /* init buffer input */
2404 c->buffer_ptr = c->buffer;
2405 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2406 c->stream->feed_opened = 1;
2407 return 0;
2408}
115329f1 2409
85f07f22
FB
2410static int http_receive_data(HTTPContext *c)
2411{
85f07f22
FB
2412 HTTPContext *c1;
2413
a6e14edd
PG
2414 if (c->buffer_end > c->buffer_ptr) {
2415 int len;
2416
c60202df 2417 len = recv(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
a6e14edd 2418 if (len < 0) {
8da4034f 2419 if (ff_neterrno() != FF_NETERROR(EAGAIN) &&
611c5741 2420 ff_neterrno() != FF_NETERROR(EINTR))
a6e14edd
PG
2421 /* error : close connection */
2422 goto fail;
611c5741 2423 } else if (len == 0)
a6e14edd
PG
2424 /* end of connection : close it */
2425 goto fail;
611c5741 2426 else {
a6e14edd
PG
2427 c->buffer_ptr += len;
2428 c->data_count += len;
5eb765ef 2429 update_datarate(&c->datarate, c->data_count);
a6e14edd
PG
2430 }
2431 }
2432
d445a7e9
PG
2433 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2434 if (c->buffer[0] != 'f' ||
2435 c->buffer[1] != 'm') {
2436 http_log("Feed stream has become desynchronized -- disconnecting\n");
2437 goto fail;
2438 }
2439 }
2440
85f07f22 2441 if (c->buffer_ptr >= c->buffer_end) {
f747e6d3 2442 FFStream *feed = c->stream;
85f07f22
FB
2443 /* a packet has been received : write it in the store, except
2444 if header */
2445 if (c->data_count > FFM_PACKET_SIZE) {
115329f1 2446
949b1a13 2447 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
85f07f22
FB
2448 /* XXX: use llseek or url_seek */
2449 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
929a9b75
BC
2450 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2451 http_log("Error writing to feed file: %s\n", strerror(errno));
2452 goto fail;
2453 }
115329f1 2454
85f07f22
FB
2455 feed->feed_write_index += FFM_PACKET_SIZE;
2456 /* update file size */
2457 if (feed->feed_write_index > c->stream->feed_size)
2458 feed->feed_size = feed->feed_write_index;
2459
2460 /* handle wrap around if max file size reached */
6b0bdc75 2461 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
85f07f22
FB
2462 feed->feed_write_index = FFM_PACKET_SIZE;
2463
2464 /* write index */
2465 ffm_write_write_index(c->feed_fd, feed->feed_write_index);
2466
2467 /* wake up any waiting connections */
2468 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
115329f1 2469 if (c1->state == HTTPSTATE_WAIT_FEED &&
611c5741 2470 c1->stream->feed == c->stream->feed)
85f07f22 2471 c1->state = HTTPSTATE_SEND_DATA;
85f07f22 2472 }
f747e6d3
PG
2473 } else {
2474 /* We have a header in our hands that contains useful data */
f2972c8c
BC
2475 AVFormatContext *s = NULL;
2476 ByteIOContext *pb;
bd7cf6ad 2477 AVInputFormat *fmt_in;
f747e6d3
PG
2478 int i;
2479
bd7cf6ad
FB
2480 /* use feed output format name to find corresponding input format */
2481 fmt_in = av_find_input_format(feed->fmt->name);
2482 if (!fmt_in)
2483 goto fail;
2484
697efa36
BC
2485 url_open_buf(&pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
2486 pb->is_streamed = 1;
2487
e6f0deab
BC
2488 if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2489 av_free(pb);
2490 goto fail;
2491 }
f747e6d3
PG
2492
2493 /* Now we have the actual streams */
f2972c8c
BC
2494 if (s->nb_streams != feed->nb_streams) {
2495 av_close_input_stream(s);
86771c68 2496 av_free(pb);
f747e6d3
PG
2497 goto fail;
2498 }
f2972c8c
BC
2499
2500 for (i = 0; i < s->nb_streams; i++)
115329f1 2501 memcpy(feed->streams[i]->codec,
f2972c8c
BC
2502 s->streams[i]->codec, sizeof(AVCodecContext));
2503
2504 av_close_input_stream(s);
86771c68 2505 av_free(pb);
85f07f22
FB
2506 }
2507 c->buffer_ptr = c->buffer;
2508 }
2509
85f07f22
FB
2510 return 0;
2511 fail:
2512 c->stream->feed_opened = 0;
2513 close(c->feed_fd);
c1593d0e
BC
2514 /* wake up any waiting connections to stop waiting for feed */
2515 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2516 if (c1->state == HTTPSTATE_WAIT_FEED &&
2517 c1->stream->feed == c->stream->feed)
2518 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2519 }
85f07f22
FB
2520 return -1;
2521}
2522
2effd274
FB
2523/********************************************************************/
2524/* RTSP handling */
2525
2526static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2527{
2528 const char *str;
2529 time_t ti;
2530 char *p;
2531 char buf2[32];
2532
2533 switch(error_number) {
7e665cd3
LA
2534 case RTSP_STATUS_OK:
2535 str = "OK";
2536 break;
2537 case RTSP_STATUS_METHOD:
2538 str = "Method Not Allowed";
2539 break;
2540 case RTSP_STATUS_BANDWIDTH:
2541 str = "Not Enough Bandwidth";
2542 break;
2543 case RTSP_STATUS_SESSION:
2544 str = "Session Not Found";
2545 break;
2546 case RTSP_STATUS_STATE:
2547 str = "Method Not Valid in This State";
2548 break;
2549 case RTSP_STATUS_AGGREGATE:
2550 str = "Aggregate operation not allowed";
2551 break;
2552 case RTSP_STATUS_ONLY_AGGREGATE:
2553 str = "Only aggregate operation allowed";
2554 break;
2555 case RTSP_STATUS_TRANSPORT:
2556 str = "Unsupported transport";
2557 break;
2558 case RTSP_STATUS_INTERNAL:
2559 str = "Internal Server Error";
2560 break;
2561 case RTSP_STATUS_SERVICE:
2562 str = "Service Unavailable";
2563 break;
2564 case RTSP_STATUS_VERSION:
2565 str = "RTSP Version not supported";
2566 break;
2effd274
FB
2567 default:
2568 str = "Unknown Error";
2569 break;
2570 }
115329f1 2571
2effd274
FB
2572 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2573 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2574
2575 /* output GMT time */
2576 ti = time(NULL);
2577 p = ctime(&ti);
2578 strcpy(buf2, p);
2579 p = buf2 + strlen(p) - 1;
2580 if (*p == '\n')
2581 *p = '\0';
2582 url_fprintf(c->pb, "Date: %s GMT\r\n", buf2);
2583}
2584
2585static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2586{
2587 rtsp_reply_header(c, error_number);
2588 url_fprintf(c->pb, "\r\n");
2589}
2590
2591static int rtsp_parse_request(HTTPContext *c)
2592{
2593 const char *p, *p1, *p2;
2594 char cmd[32];
2595 char url[1024];
2596 char protocol[32];
2597 char line[1024];
2effd274
FB
2598 int len;
2599 RTSPHeader header1, *header = &header1;
115329f1 2600
2effd274
FB
2601 c->buffer_ptr[0] = '\0';
2602 p = c->buffer;
115329f1 2603
2effd274
FB
2604 get_word(cmd, sizeof(cmd), &p);
2605 get_word(url, sizeof(url), &p);
2606 get_word(protocol, sizeof(protocol), &p);
2607
f7d78f36
MR
2608 av_strlcpy(c->method, cmd, sizeof(c->method));
2609 av_strlcpy(c->url, url, sizeof(c->url));
2610 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2effd274 2611
899681cd 2612 if (url_open_dyn_buf(&c->pb) < 0) {
2effd274
FB
2613 /* XXX: cannot do more */
2614 c->pb = NULL; /* safety */
2615 return -1;
2616 }
2617
2618 /* check version name */
2619 if (strcmp(protocol, "RTSP/1.0") != 0) {
2620 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2621 goto the_end;
2622 }
2623
2624 /* parse each header line */
2625 memset(header, 0, sizeof(RTSPHeader));
2626 /* skip to next line */
2627 while (*p != '\n' && *p != '\0')
2628 p++;
2629 if (*p == '\n')
2630 p++;
2631 while (*p != '\0') {
2632 p1 = strchr(p, '\n');
2633 if (!p1)
2634 break;
2635 p2 = p1;
2636 if (p2 > p && p2[-1] == '\r')
2637 p2--;
2638 /* skip empty line */
2639 if (p2 == p)
2640 break;
2641 len = p2 - p;
2642 if (len > sizeof(line) - 1)
2643 len = sizeof(line) - 1;
2644 memcpy(line, p, len);
2645 line[len] = '\0';
2646 rtsp_parse_line(header, line);
2647 p = p1 + 1;
2648 }
2649
2650 /* handle sequence number */
2651 c->seq = header->seq;
2652
611c5741 2653 if (!strcmp(cmd, "DESCRIBE"))
2effd274 2654 rtsp_cmd_describe(c, url);
611c5741 2655 else if (!strcmp(cmd, "OPTIONS"))
0df65975 2656 rtsp_cmd_options(c, url);
611c5741 2657 else if (!strcmp(cmd, "SETUP"))
2effd274 2658 rtsp_cmd_setup(c, url, header);
611c5741 2659 else if (!strcmp(cmd, "PLAY"))
2effd274 2660 rtsp_cmd_play(c, url, header);
611c5741 2661 else if (!strcmp(cmd, "PAUSE"))
2effd274 2662 rtsp_cmd_pause(c, url, header);
611c5741 2663 else if (!strcmp(cmd, "TEARDOWN"))
2effd274 2664 rtsp_cmd_teardown(c, url, header);
611c5741 2665 else
2effd274 2666 rtsp_reply_error(c, RTSP_STATUS_METHOD);
611c5741 2667
2effd274
FB
2668 the_end:
2669 len = url_close_dyn_buf(c->pb, &c->pb_buffer);
2670 c->pb = NULL; /* safety */
2671 if (len < 0) {
2672 /* XXX: cannot do more */
2673 return -1;
2674 }
2675 c->buffer_ptr = c->pb_buffer;
2676 c->buffer_end = c->pb_buffer + len;
2677 c->state = RTSPSTATE_SEND_REPLY;
2678 return 0;
2679}
2680
115329f1 2681static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
829ac53d 2682 struct in_addr my_ip)
2effd274 2683{
dd723472
LA
2684 AVFormatContext *avc;
2685 AVStream avs[MAX_STREAMS];
2686 int i;
115329f1 2687
dd723472
LA
2688 avc = av_alloc_format_context();
2689 if (avc == NULL) {
2effd274 2690 return -1;
dd723472
LA
2691 }
2692 if (stream->title[0] != 0) {
2693 av_strlcpy(avc->title, stream->title, sizeof(avc->title));
2694 } else {
2695 av_strlcpy(avc->title, "No Title", sizeof(avc->title));
2696 }
2697 avc->nb_streams = stream->nb_streams;
2698 if (stream->is_multicast) {
2699 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2700 inet_ntoa(stream->multicast_ip),
2701 stream->multicast_port, stream->multicast_ttl);
2702 }
115329f1 2703
2effd274 2704 for(i = 0; i < stream->nb_streams; i++) {
dd723472
LA
2705 avc->streams[i] = &avs[i];
2706 avc->streams[i]->codec = stream->streams[i]->codec;
2effd274 2707 }
dd723472
LA
2708 *pbuffer = av_mallocz(2048);
2709 avf_sdp_create(&avc, 1, *pbuffer, 2048);
2710 av_free(avc);
2711
2712 return strlen(*pbuffer);
2effd274
FB
2713}
2714
0df65975
AR
2715static void rtsp_cmd_options(HTTPContext *c, const char *url)
2716{
2717// rtsp_reply_header(c, RTSP_STATUS_OK);
2718 url_fprintf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2719 url_fprintf(c->pb, "CSeq: %d\r\n", c->seq);
2720 url_fprintf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2721 url_fprintf(c->pb, "\r\n");
2722}
2723
2effd274
FB
2724static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2725{
2726 FFStream *stream;
2727 char path1[1024];
2728 const char *path;
0c1a9eda 2729 uint8_t *content;
829ac53d
FB
2730 int content_length, len;
2731 struct sockaddr_in my_addr;
115329f1 2732
2effd274 2733 /* find which url is asked */
6ba5cbc6 2734 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
2735 path = path1;
2736 if (*path == '/')
2737 path++;
2738
2739 for(stream = first_stream; stream != NULL; stream = stream->next) {
25e3e53d
LA
2740 if (!stream->is_feed &&
2741 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2effd274
FB
2742 !strcmp(path, stream->filename)) {
2743 goto found;
2744 }
2745 }
2746 /* no stream found */
2747 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2748 return;
2749
2750 found:
2751 /* prepare the media description in sdp format */
829ac53d
FB
2752
2753 /* get the host IP */
2754 len = sizeof(my_addr);
2755 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
829ac53d 2756 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2effd274
FB
2757 if (content_length < 0) {
2758 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2759 return;
2760 }
2761 rtsp_reply_header(c, RTSP_STATUS_OK);
2762 url_fprintf(c->pb, "Content-Type: application/sdp\r\n");
2763 url_fprintf(c->pb, "Content-Length: %d\r\n", content_length);
2764 url_fprintf(c->pb, "\r\n");
2765 put_buffer(c->pb, content, content_length);
2766}
2767
2768static HTTPContext *find_rtp_session(const char *session_id)
2769{
2770 HTTPContext *c;
2771
2772 if (session_id[0] == '\0')
2773 return NULL;
2774
2775 for(c = first_http_ctx; c != NULL; c = c->next) {
2776 if (!strcmp(c->session_id, session_id))
2777 return c;
2778 }
2779 return NULL;
2780}
2781
b29f97d1 2782static RTSPTransportField *find_transport(RTSPHeader *h, enum RTSPProtocol protocol)
2effd274
FB
2783{
2784 RTSPTransportField *th;
2785 int i;
2786
2787 for(i=0;i<h->nb_transports;i++) {
2788 th = &h->transports[i];
2789 if (th->protocol == protocol)
2790 return th;
2791 }
2792 return NULL;
2793}
2794
115329f1 2795static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2effd274
FB
2796 RTSPHeader *h)
2797{
2798 FFStream *stream;
2799 int stream_index, port;
2800 char buf[1024];
2801 char path1[1024];
2802 const char *path;
2803 HTTPContext *rtp_c;
2804 RTSPTransportField *th;
2805 struct sockaddr_in dest_addr;
2806 RTSPActionServerSetup setup;
115329f1 2807
2effd274 2808 /* find which url is asked */
6ba5cbc6 2809 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
2810 path = path1;
2811 if (*path == '/')
2812 path++;
2813
2814 /* now check each stream */
2815 for(stream = first_stream; stream != NULL; stream = stream->next) {
25e3e53d
LA
2816 if (!stream->is_feed &&
2817 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2effd274
FB
2818 /* accept aggregate filenames only if single stream */
2819 if (!strcmp(path, stream->filename)) {
2820 if (stream->nb_streams != 1) {
2821 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2822 return;
2823 }
2824 stream_index = 0;
2825 goto found;
2826 }
115329f1 2827
2effd274
FB
2828 for(stream_index = 0; stream_index < stream->nb_streams;
2829 stream_index++) {
115329f1 2830 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2effd274
FB
2831 stream->filename, stream_index);
2832 if (!strcmp(path, buf))
2833 goto found;
2834 }
2835 }
2836 }
2837 /* no stream found */
2838 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2839 return;
2840 found:
2841
2842 /* generate session id if needed */
611c5741 2843 if (h->session_id[0] == '\0')
1df93ae9
AB
2844 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2845 av_random(&random_state), av_random(&random_state));
2effd274
FB
2846
2847 /* find rtp session, and create it if none found */
2848 rtp_c = find_rtp_session(h->session_id);
2849 if (!rtp_c) {
bc351386
FB
2850 /* always prefer UDP */
2851 th = find_transport(h, RTSP_PROTOCOL_RTP_UDP);
2852 if (!th) {
2853 th = find_transport(h, RTSP_PROTOCOL_RTP_TCP);
2854 if (!th) {
2855 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2856 return;
2857 }
2858 }
2859
2860 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2861 th->protocol);
2effd274
FB
2862 if (!rtp_c) {
2863 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2864 return;
2865 }
2866
2867 /* open input stream */
2868 if (open_input_stream(rtp_c, "") < 0) {
2869 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2870 return;
2871 }
2effd274 2872 }
115329f1 2873
2effd274
FB
2874 /* test if stream is OK (test needed because several SETUP needs
2875 to be done for a given file) */
2876 if (rtp_c->stream != stream) {
2877 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2878 return;
2879 }
115329f1 2880
2effd274
FB
2881 /* test if stream is already set up */
2882 if (rtp_c->rtp_ctx[stream_index]) {
2883 rtsp_reply_error(c, RTSP_STATUS_STATE);
2884 return;
2885 }
2886
2887 /* check transport */
2888 th = find_transport(h, rtp_c->rtp_protocol);
115329f1 2889 if (!th || (th->protocol == RTSP_PROTOCOL_RTP_UDP &&
2effd274
FB
2890 th->client_port_min <= 0)) {
2891 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2892 return;
2893 }
2894
2895 /* setup default options */
2896 setup.transport_option[0] = '\0';
2897 dest_addr = rtp_c->from_addr;
2898 dest_addr.sin_port = htons(th->client_port_min);
115329f1 2899
2effd274 2900 /* setup stream */
bc351386 2901 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2effd274
FB
2902 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2903 return;
2904 }
2905
2906 /* now everything is OK, so we can send the connection parameters */
2907 rtsp_reply_header(c, RTSP_STATUS_OK);
2908 /* session ID */
2909 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2910
2911 switch(rtp_c->rtp_protocol) {
2912 case RTSP_PROTOCOL_RTP_UDP:
2913 port = rtp_get_local_port(rtp_c->rtp_handles[stream_index]);
2914 url_fprintf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
2915 "client_port=%d-%d;server_port=%d-%d",
2916 th->client_port_min, th->client_port_min + 1,
2917 port, port + 1);
2918 break;
2919 case RTSP_PROTOCOL_RTP_TCP:
2920 url_fprintf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
2921 stream_index * 2, stream_index * 2 + 1);
2922 break;
2923 default:
2924 break;
2925 }
611c5741 2926 if (setup.transport_option[0] != '\0')
2effd274 2927 url_fprintf(c->pb, ";%s", setup.transport_option);
2effd274 2928 url_fprintf(c->pb, "\r\n");
115329f1 2929
2effd274
FB
2930
2931 url_fprintf(c->pb, "\r\n");
2932}
2933
2934
2935/* find an rtp connection by using the session ID. Check consistency
2936 with filename */
115329f1 2937static HTTPContext *find_rtp_session_with_url(const char *url,
2effd274
FB
2938 const char *session_id)
2939{
2940 HTTPContext *rtp_c;
2941 char path1[1024];
2942 const char *path;
94d9ad5f
GF
2943 char buf[1024];
2944 int s;
2effd274
FB
2945
2946 rtp_c = find_rtp_session(session_id);
2947 if (!rtp_c)
2948 return NULL;
2949
2950 /* find which url is asked */
6ba5cbc6 2951 url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2effd274
FB
2952 path = path1;
2953 if (*path == '/')
2954 path++;
94d9ad5f
GF
2955 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
2956 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
2957 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2958 rtp_c->stream->filename, s);
2959 if(!strncmp(path, buf, sizeof(buf))) {
2960 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
2961 return rtp_c;
2962 }
2963 }
2964 return NULL;
2effd274
FB
2965}
2966
2967static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPHeader *h)
2968{
2969 HTTPContext *rtp_c;
2970
2971 rtp_c = find_rtp_session_with_url(url, h->session_id);
2972 if (!rtp_c) {
2973 rtsp_reply_error(c, RTSP_STATUS_SESSION);
2974 return;
2975 }
115329f1 2976
2effd274
FB
2977 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
2978 rtp_c->state != HTTPSTATE_WAIT_FEED &&
2979 rtp_c->state != HTTPSTATE_READY) {
2980 rtsp_reply_error(c, RTSP_STATUS_STATE);
2981 return;
2982 }
2983
e240a0bb
FB
2984#if 0
2985 /* XXX: seek in stream */
2986 if (h->range_start != AV_NOPTS_VALUE) {
2987 printf("range_start=%0.3f\n", (double)h->range_start / AV_TIME_BASE);
2988 av_seek_frame(rtp_c->fmt_in, -1, h->range_start);
2989 }
2990#endif
2991
2effd274 2992 rtp_c->state = HTTPSTATE_SEND_DATA;
115329f1 2993
2effd274
FB
2994 /* now everything is OK, so we can send the connection parameters */
2995 rtsp_reply_header(c, RTSP_STATUS_OK);
2996 /* session ID */
2997 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
2998 url_fprintf(c->pb, "\r\n");
2999}
3000
3001static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPHeader *h)
3002{
3003 HTTPContext *rtp_c;
3004
3005 rtp_c = find_rtp_session_with_url(url, h->session_id);
3006 if (!rtp_c) {
3007 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3008 return;
3009 }
115329f1 3010
2effd274
FB
3011 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3012 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3013 rtsp_reply_error(c, RTSP_STATUS_STATE);
3014 return;
3015 }
115329f1 3016
2effd274 3017 rtp_c->state = HTTPSTATE_READY;
1bc1cfdd 3018 rtp_c->first_pts = AV_NOPTS_VALUE;
2effd274
FB
3019 /* now everything is OK, so we can send the connection parameters */
3020 rtsp_reply_header(c, RTSP_STATUS_OK);
3021 /* session ID */
3022 url_fprintf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3023 url_fprintf(c->pb, "\r\n");
3024}
3025
3026static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPHeader *h)
3027{
3028 HTTPContext *rtp_c;
b0b2faa7 3029 char session_id[32];
2effd274
FB
3030
3031 rtp_c = find_rtp_session_with_url(url, h->session_id);
3032 if (!rtp_c) {
3033 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3034 return;
3035 }
115329f1 3036
f7d78f36 3037 av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
b0b2faa7 3038
2effd274
FB
3039 /* abort the session */
3040 close_connection(rtp_c);
3041
2effd274
FB
3042 /* now everything is OK, so we can send the connection parameters */
3043 rtsp_reply_header(c, RTSP_STATUS_OK);
3044 /* session ID */
b0b2faa7 3045 url_fprintf(c->pb, "Session: %s\r\n", session_id);
2effd274
FB
3046 url_fprintf(c->pb, "\r\n");
3047}
3048
3049
3050/********************************************************************/
3051/* RTP handling */
3052
115329f1 3053static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
bc351386
FB
3054 FFStream *stream, const char *session_id,
3055 enum RTSPProtocol rtp_protocol)
2effd274
FB
3056{
3057 HTTPContext *c = NULL;
bc351386 3058 const char *proto_str;
115329f1 3059
2effd274
FB
3060 /* XXX: should output a warning page when coming
3061 close to the connection limit */
3062 if (nb_connections >= nb_max_connections)
3063 goto fail;
115329f1 3064
2effd274
FB
3065 /* add a new connection */
3066 c = av_mallocz(sizeof(HTTPContext));
3067 if (!c)
3068 goto fail;
115329f1 3069
2effd274
FB
3070 c->fd = -1;
3071 c->poll_entry = NULL;
6edd6884 3072 c->from_addr = *from_addr;
2effd274
FB
3073 c->buffer_size = IOBUFFER_INIT_SIZE;
3074 c->buffer = av_malloc(c->buffer_size);
3075 if (!c->buffer)
3076 goto fail;
3077 nb_connections++;
3078 c->stream = stream;
f7d78f36 3079 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
2effd274
FB
3080 c->state = HTTPSTATE_READY;
3081 c->is_packetized = 1;
bc351386
FB
3082 c->rtp_protocol = rtp_protocol;
3083
2effd274 3084 /* protocol is shown in statistics */
bc351386
FB
3085 switch(c->rtp_protocol) {
3086 case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3087 proto_str = "MCAST";
3088 break;
3089 case RTSP_PROTOCOL_RTP_UDP:
3090 proto_str = "UDP";
3091 break;
3092 case RTSP_PROTOCOL_RTP_TCP:
3093 proto_str = "TCP";
3094 break;
3095 default:
3096 proto_str = "???";
3097 break;
3098 }
f7d78f36
MR
3099 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3100 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
2effd274 3101
6edd6884
FB
3102 current_bandwidth += stream->bandwidth;
3103
2effd274
FB
3104 c->next = first_http_ctx;
3105 first_http_ctx = c;
3106 return c;
115329f1 3107
2effd274
FB
3108 fail:
3109 if (c) {
3110 av_free(c->buffer);
3111 av_free(c);
3112 }
3113 return NULL;
3114}
3115
3116/* add a new RTP stream in an RTP connection (used in RTSP SETUP
bc351386 3117 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
2effd274 3118 used. */
115329f1 3119static int rtp_new_av_stream(HTTPContext *c,
bc351386
FB
3120 int stream_index, struct sockaddr_in *dest_addr,
3121 HTTPContext *rtsp_c)
2effd274
FB
3122{
3123 AVFormatContext *ctx;
3124 AVStream *st;
3125 char *ipaddr;
75480e86 3126 URLContext *h = NULL;
0c1a9eda 3127 uint8_t *dummy_buf;
bc351386 3128 int max_packet_size;
115329f1 3129
2effd274 3130 /* now we can open the relevant output stream */
bc874dae 3131 ctx = av_alloc_format_context();
2effd274
FB
3132 if (!ctx)
3133 return -1;
b156b88c 3134 ctx->oformat = guess_format("rtp", NULL, NULL);
2effd274
FB
3135
3136 st = av_mallocz(sizeof(AVStream));
3137 if (!st)
3138 goto fail;
8d931070 3139 st->codec= avcodec_alloc_context();
2effd274
FB
3140 ctx->nb_streams = 1;
3141 ctx->streams[0] = st;
3142
115329f1 3143 if (!c->stream->feed ||
611c5741 3144 c->stream->feed == c->stream)
2effd274 3145 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
611c5741 3146 else
115329f1 3147 memcpy(st,
2effd274
FB
3148 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3149 sizeof(AVStream));
57dbe08b 3150 st->priv_data = NULL;
115329f1 3151
bc351386
FB
3152 /* build destination RTP address */
3153 ipaddr = inet_ntoa(dest_addr->sin_addr);
3154
3155 switch(c->rtp_protocol) {
3156 case RTSP_PROTOCOL_RTP_UDP:
3157 case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
3158 /* RTP/UDP case */
115329f1 3159
6edd6884
FB
3160 /* XXX: also pass as parameter to function ? */
3161 if (c->stream->is_multicast) {
3162 int ttl;
3163 ttl = c->stream->multicast_ttl;
3164 if (!ttl)
3165 ttl = 16;
3166 snprintf(ctx->filename, sizeof(ctx->filename),
115329f1 3167 "rtp://%s:%d?multicast=1&ttl=%d",
6edd6884
FB
3168 ipaddr, ntohs(dest_addr->sin_port), ttl);
3169 } else {
3170 snprintf(ctx->filename, sizeof(ctx->filename),
3171 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3172 }
2effd274
FB
3173
3174 if (url_open(&h, ctx->filename, URL_WRONLY) < 0)
3175 goto fail;
3176 c->rtp_handles[stream_index] = h;
bc351386
FB
3177 max_packet_size = url_get_max_packet_size(h);
3178 break;
3179 case RTSP_PROTOCOL_RTP_TCP:
3180 /* RTP/TCP case */
3181 c->rtsp_c = rtsp_c;
3182 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3183 break;
3184 default:
2effd274
FB
3185 goto fail;
3186 }
3187
e21ac209 3188 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
115329f1 3189 ipaddr, ntohs(dest_addr->sin_port),
bc351386 3190 c->stream->filename, stream_index, c->protocol);
6edd6884 3191
2effd274 3192 /* normally, no packets should be output here, but the packet size may be checked */
bc351386 3193 if (url_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
2effd274
FB
3194 /* XXX: close stream */
3195 goto fail;
3196 }
3c27199b 3197 av_set_parameters(ctx, NULL);
2effd274
FB
3198 if (av_write_header(ctx) < 0) {
3199 fail:
3200 if (h)
3201 url_close(h);
3202 av_free(ctx);
3203 return -1;
3204 }
899681cd 3205 url_close_dyn_buf(ctx->pb, &dummy_buf);
2effd274 3206 av_free(dummy_buf);
115329f1 3207
2effd274
FB
3208 c->rtp_ctx[stream_index] = ctx;
3209 return 0;
3210}
3211
3212/********************************************************************/
3213/* ffserver initialization */
3214
b29f97d1 3215static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec)
2effd274
FB
3216{
3217 AVStream *fst;
3218
3219 fst = av_mallocz(sizeof(AVStream));
3220 if (!fst)
3221 return NULL;
8d931070 3222 fst->codec= avcodec_alloc_context();
2effd274 3223 fst->priv_data = av_mallocz(sizeof(FeedData));
01f4895c 3224 memcpy(fst->codec, codec, sizeof(AVCodecContext));
d445a7e9 3225 fst->index = stream->nb_streams;
7c054ea7 3226 av_set_pts_info(fst, 33, 1, 90000);
2effd274
FB
3227 stream->streams[stream->nb_streams++] = fst;
3228 return fst;
3229}
3230
85f07f22 3231/* return the stream number in the feed */
b29f97d1 3232static int add_av_stream(FFStream *feed, AVStream *st)
85f07f22
FB
3233{
3234 AVStream *fst;
3235 AVCodecContext *av, *av1;
3236 int i;
3237
01f4895c 3238 av = st->codec;
85f07f22
FB
3239 for(i=0;i<feed->nb_streams;i++) {
3240 st = feed->streams[i];
01f4895c 3241 av1 = st->codec;
f747e6d3
PG
3242 if (av1->codec_id == av->codec_id &&
3243 av1->codec_type == av->codec_type &&
85f07f22
FB
3244 av1->bit_rate == av->bit_rate) {
3245
3246 switch(av->codec_type) {
3247 case CODEC_TYPE_AUDIO:
3248 if (av1->channels == av->channels &&
3249 av1->sample_rate == av->sample_rate)
3250 goto found;
3251 break;
3252 case CODEC_TYPE_VIDEO:
3253 if (av1->width == av->width &&
3254 av1->height == av->height &&
c0df9d75
MN
3255 av1->time_base.den == av->time_base.den &&
3256 av1->time_base.num == av->time_base.num &&
85f07f22
FB
3257 av1->gop_size == av->gop_size)
3258 goto found;
3259 break;
f747e6d3 3260 default:
0f4e8165 3261 abort();
85f07f22
FB
3262 }
3263 }
3264 }
115329f1 3265
2effd274 3266 fst = add_av_stream1(feed, av);
85f07f22
FB
3267 if (!fst)
3268 return -1;
85f07f22
FB
3269 return feed->nb_streams - 1;
3270 found:
3271 return i;
3272}
3273
b29f97d1 3274static void remove_stream(FFStream *stream)
2effd274
FB
3275{
3276 FFStream **ps;
3277 ps = &first_stream;
3278 while (*ps != NULL) {
611c5741 3279 if (*ps == stream)
2effd274 3280 *ps = (*ps)->next;
611c5741 3281 else
2effd274 3282 ps = &(*ps)->next;
2effd274
FB
3283 }
3284}
3285
0fa45e19 3286/* specific mpeg4 handling : we extract the raw parameters */
b29f97d1 3287static void extract_mpeg4_header(AVFormatContext *infile)
0fa45e19
FB
3288{
3289 int mpeg4_count, i, size;
3290 AVPacket pkt;
3291 AVStream *st;
0c1a9eda 3292 const uint8_t *p;
0fa45e19
FB
3293
3294 mpeg4_count = 0;
3295 for(i=0;i<infile->nb_streams;i++) {
3296 st = infile->streams[i];
01f4895c
MN
3297 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3298 st->codec->extradata_size == 0) {
0fa45e19
FB
3299 mpeg4_count++;
3300 }
3301 }
3302 if (!mpeg4_count)
3303 return;
3304
d445a7e9 3305 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
0fa45e19
FB
3306 while (mpeg4_count > 0) {
3307 if (av_read_packet(infile, &pkt) < 0)
3308 break;
3309 st = infile->streams[pkt.stream_index];
01f4895c
MN
3310 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3311 st->codec->extradata_size == 0) {
3312 av_freep(&st->codec->extradata);
0fa45e19
FB
3313 /* fill extradata with the header */
3314 /* XXX: we make hard suppositions here ! */
3315 p = pkt.data;
3316 while (p < pkt.data + pkt.size - 4) {
3317 /* stop when vop header is found */
115329f1 3318 if (p[0] == 0x00 && p[1] == 0x00 &&
0fa45e19
FB
3319 p[2] == 0x01 && p[3] == 0xb6) {
3320 size = p - pkt.data;
750f0e1f 3321 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
01f4895c
MN
3322 st->codec->extradata = av_malloc(size);
3323 st->codec->extradata_size = size;
3324 memcpy(st->codec->extradata, pkt.data, size);
0fa45e19
FB
3325 break;
3326 }
3327 p++;
3328 }
3329 mpeg4_count--;
3330 }
3331 av_free_packet(&pkt);
3332 }
3333}
3334
2effd274 3335/* compute the needed AVStream for each file */
b29f97d1 3336static void build_file_streams(void)
2effd274
FB
3337{
3338 FFStream *stream, *stream_next;
3339 AVFormatContext *infile;
f61d45c9 3340 int i, ret;
2effd274
FB
3341
3342 /* gather all streams */
3343 for(stream = first_stream; stream != NULL; stream = stream_next) {
3344 stream_next = stream->next;
3345 if (stream->stream_type == STREAM_TYPE_LIVE &&
3346 !stream->feed) {
3347 /* the stream comes from a file */
3348 /* try to open the file */
3349 /* open stream */
e240a0bb 3350 stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
25e3e53d 3351 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
e240a0bb
FB
3352 /* specific case : if transport stream output to RTP,
3353 we use a raw transport stream reader */
3354 stream->ap_in->mpeg2ts_raw = 1;
3355 stream->ap_in->mpeg2ts_compute_pcr = 1;
3356 }
115329f1 3357
f61d45c9
BC
3358 if ((ret = av_open_input_file(&infile, stream->feed_filename,
3359 stream->ifmt, 0, stream->ap_in)) < 0) {
3360 http_log("could not open %s: %d\n", stream->feed_filename, ret);
2effd274
FB
3361 /* remove stream (no need to spend more time on it) */
3362 fail:
3363 remove_stream(stream);
3364 } else {
3365 /* find all the AVStreams inside and reference them in
3366 'stream' */
3367 if (av_find_stream_info(infile) < 0) {
2dae1dd0 3368 http_log("Could not find codec parameters from '%s'\n",
2effd274
FB
3369 stream->feed_filename);
3370 av_close_input_file(infile);
3371 goto fail;
3372 }
0fa45e19
FB
3373 extract_mpeg4_header(infile);
3374
611c5741 3375 for(i=0;i<infile->nb_streams;i++)
01f4895c 3376 add_av_stream1(stream, infile->streams[i]->codec);
611c5741 3377
2effd274
FB
3378 av_close_input_file(infile);
3379 }
3380