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