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