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