⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ffserver.c

📁 杜比AC-3编码解码器(参考程序)
💻 C
📖 第 1 页 / 共 4 页
字号:
        } while (ret == -1);
        
        cur_time = gettime_ms();

        /* now handle the events */

        cp = &first_http_ctx;
        while ((*cp) != NULL) {
            c = *cp;
            if (handle_http (c, cur_time) < 0) {
                /* close and free the connection */
                close(c->fd);
                *cp = c->next;
                free(c);
                nb_connections--;
            } else {
                cp = &c->next;
            }
        }

        /* new connection request ? */
        poll_entry = poll_table;
        if (poll_entry->revents & POLLIN) {
            int fd, len;

            len = sizeof(from_addr);
            fd = accept(server_fd, &from_addr, &len);
            if (fd >= 0) {
                fcntl(fd, F_SETFL, O_NONBLOCK);
                /* XXX: should output a warning page when comming
                   close to the connection limit */
                if (nb_connections >= nb_max_connections) {
                    close(fd);
                } else {
                    /* add a new connection */
                    c = malloc(sizeof(HTTPContext));
                    memset(c, 0, sizeof(*c));
                    c->next = first_http_ctx;
                    first_http_ctx = c;
                    c->fd = fd;
                    c->poll_entry = NULL;
                    c->from_addr = from_addr;
                    c->state = HTTPSTATE_WAIT_REQUEST;
                    c->buffer_ptr = c->buffer;
                    c->buffer_end = c->buffer + IOBUFFER_MAX_SIZE;
                    c->timeout = cur_time + REQUEST_TIMEOUT;
                    nb_connections++;
                }
            }
        }
        poll_entry++;

        /* master events */
        if (poll_entry->revents & POLLIN) {
            if (master_receive(master_fd) < 0) {
                close(master_fd);
                master_fd = -1;
            }
        }

        /* master (re)connection handling */
        if (master_url[0] != '\0' && 
            master_fd < 0 && (master_timeout - cur_time) <= 0) {
            master_fd = url_get(master_url);
            if (master_fd < 0) {
                master_timeout = gettime_ms() + MASTER_CONNECT_TIMEOUT;
                http_log("Connection to master: '%s' failed\n", master_url);
            } else {
                fcntl(master_fd, F_SETFL, O_NONBLOCK);
                master_state = MASTERSTATE_RECEIVE_HEADER;
                master_count = sizeof(PacketHeader);
                master_wptr = http_fifo.wptr;
            }
        }
    }
}

static int handle_http(HTTPContext *c, long cur_time)
{
    int len;
    
    switch(c->state) {
    case HTTPSTATE_WAIT_REQUEST:
        /* timeout ? */
        if ((c->timeout - cur_time) < 0)
            return -1;
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

        /* no need to read if no events */
        if (!(c->poll_entry->revents & POLLIN))
            return 0;
        /* read the data */
        len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
        if (len < 0) {
            if (errno != EAGAIN && errno != EINTR)
                return -1;
        } else if (len == 0) {
            return -1;
        } else {
            /* search for end of request. XXX: not fully correct since garbage could come after the end */
            UINT8 *ptr;
            c->buffer_ptr += len;
            ptr = c->buffer_ptr;
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
                /* request found : parse it and reply */
                if (http_parse_request(c) < 0)
                    return -1;
            } else if (ptr >= c->buffer_end) {
                /* request too long: cannot do anything */
                return -1;
            }
        }
        break;

    case HTTPSTATE_SEND_HEADER:
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

        /* no need to read if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
        len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
        if (len < 0) {
            if (errno != EAGAIN && errno != EINTR) {
                /* error : close connection */
                return -1;
            }
        } else {
            c->buffer_ptr += len;
            if (c->buffer_ptr >= c->buffer_end) {
                /* if error, exit */
                if (c->http_error)
                    return -1;
                /* all the buffer was send : synchronize to the incoming stream */
                c->state = HTTPSTATE_SEND_DATA_HEADER;
                c->buffer_ptr = c->buffer_end = c->buffer;
            }
        }
        break;

    case HTTPSTATE_SEND_DATA:
    case HTTPSTATE_SEND_DATA_HEADER:
    case HTTPSTATE_SEND_DATA_TRAILER:
        /* no need to read if no events */
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;
        
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
        if (http_send_data(c) < 0)
            return -1;
        break;
    default:
        return -1;
    }
    return 0;
}

/* parse http request and prepare header */
static int http_parse_request(HTTPContext *c)
{
    const char *p;
    char cmd[32];
    char url[1024], *q;
    char protocol[32];
    char msg[1024];
    char *mime_type;
    FFStream *stream;

    p = c->buffer;
    q = cmd;
    while (!isspace(*p) && *p != '\0') {
        if ((q - cmd) < sizeof(cmd) - 1)
            *q++ = *p;
        p++;
    }
    *q = '\0';
    if (strcmp(cmd, "GET"))
        return -1;

    while (isspace(*p)) p++;
    q = url;
    while (!isspace(*p) && *p != '\0') {
        if ((q - url) < sizeof(url) - 1)
            *q++ = *p;
        p++;
    }
    *q = '\0';

    while (isspace(*p)) p++;
    q = protocol;
    while (!isspace(*p) && *p != '\0') {
        if ((q - protocol) < sizeof(protocol) - 1)
            *q++ = *p;
        p++;
    }
    *q = '\0';
    if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
        return -1;
    
    /* find the filename in the request */
    p = url;
    if (*p == '/')
        p++;

    stream = first_stream;
    while (stream != NULL) {
        if (!strcmp(stream->filename, p))
            break;
        stream = stream->next;
    }
    if (stream == NULL) {
        sprintf(msg, "File '%s' not found", url);
        goto send_error;
    }
    c->stream = stream;
    
    /* should do it after so that the size can be computed */
    {
        char buf1[32], buf2[32], *p;
        time_t ti;
        /* XXX: reentrant function ? */
        p = inet_ntoa(c->from_addr.sin_addr);
        strcpy(buf1, p);
        ti = time(NULL);
        p = ctime(&ti);
        strcpy(buf2, p);
        p = buf2 + strlen(p) - 1;
        if (*p == '\n')
            *p = '\0';
        http_log("%s - - [%s] \"%s %s %s\" %d %d\n", 
                 buf1, buf2, cmd, url, protocol, 200, 1024);
    }

    if (c->stream->stream_type == STREAM_TYPE_STATUS)
        goto send_stats;

    /* prepare http header */
    q = c->buffer;
    q += sprintf(q, "HTTP/1.0 200 OK\r\n");
    mime_type = c->stream->fmt->mime_type;
    if (!mime_type)
        mime_type = "application/x-octet_stream";
    q += sprintf(q, "Content-type: %s\r\n", mime_type);
    q += sprintf(q, "Pragma: no-cache\r\n");
    /* for asf, we need extra headers */
    if (!strcmp(c->stream->fmt->name,"asf")) {
        q += sprintf(q, "Pragma: features=broadcast\r\n");
    }
    q += sprintf(q, "\r\n");

    /* prepare output buffer */
    c->http_error = 0;
    c->buffer_ptr = c->buffer;
    c->buffer_end = q;
    c->state = HTTPSTATE_SEND_HEADER;
    return 0;
 send_error:
    c->http_error = 404;
    q = c->buffer;
    q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
    q += sprintf(q, "Content-type: %s\r\n", "text/html");
    q += sprintf(q, "\r\n");
    q += sprintf(q, "<HTML>\n");
    q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
    q += sprintf(q, "<BODY>%s</BODY>\n", msg);
    q += sprintf(q, "</HTML>\n");

    /* prepare output buffer */
    c->buffer_ptr = c->buffer;
    c->buffer_end = q;
    c->state = HTTPSTATE_SEND_HEADER;
    return 0;
 send_stats:
    compute_stats(c);
    c->http_error = 200; /* horrible : we use this value to avoid
                            going to the send data state */
    c->state = HTTPSTATE_SEND_HEADER;
    return 0;
}

static void compute_stats(HTTPContext *c)
{
    AVEncodeContext *enc;
    HTTPContext *c1;
    FFCodec *ffenc;
    FFStream *stream;
    float avg;
    char buf[1024], *q, *p;
    time_t ti;
    int i;

    q = c->buffer;
    q += sprintf(q, "HTTP/1.0 200 OK\r\n");
    q += sprintf(q, "Content-type: %s\r\n", "text/html");
    q += sprintf(q, "Pragma: no-cache\r\n");
    q += sprintf(q, "\r\n");
    
    q += sprintf(q, "<HEAD><TITLE>FFServer Status</TITLE></HEAD>\n<BODY>");
    q += sprintf(q, "<H1>FFServer Status</H1>\n");
    /* format status */
    q += sprintf(q, "<H1>Available Streams</H1>\n");
    q += sprintf(q, "<TABLE>\n");
    q += sprintf(q, "<TR><TD>Path<TD>Format<TD>Bit rate (kbits/s)<TD>Video<TD>Audio\n");
    stream = first_stream;
    while (stream != NULL) {
        q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
                     stream->filename, stream->filename);
        switch(stream->stream_type) {
        case STREAM_TYPE_LIVE:
            {
                int audio_bit_rate = 0;
                int video_bit_rate = 0;
                if (stream->audio_enc)
                    audio_bit_rate = stream->audio_enc->bit_rate;
                if (stream->video_enc)
                    video_bit_rate = stream->video_enc->bit_rate;
                
                q += sprintf(q, "<TD> %s <TD> %d <TD> %d <TD> %d\n", 
                             stream->fmt->name,
                             (audio_bit_rate + video_bit_rate) / 1000,
                             video_bit_rate / 1000, audio_bit_rate / 1000);
            }
            break;
        case STREAM_TYPE_MASTER:
            q += sprintf(q, "<TD> %s <TD> - <TD> - <TD> -\n",
                         "master");
            break;
        default:
            q += sprintf(q, "<TD> - <TD> - <TD> - <TD> -\n");
            break;
        }
        stream = stream->next;
    }
    q += sprintf(q, "</TABLE>\n");
    
    /* codec status */
    q += sprintf(q, "<H1>Codec Status</H1>\n");
    q += sprintf(q, "<TABLE>\n");
    q += sprintf(q, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
    ffenc = first_codec;
    while (ffenc != NULL) {
        enc = &ffenc->enc;
        avencoder_string(buf, sizeof(buf), enc);
        avg = ffenc->avg_frame_size * (float)enc->rate * 8.0;
        if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
            avg /= enc->frame_size;
        q += sprintf(q, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
                     buf, enc->frame_number, ffenc->data_count, avg / 1000.0);
        ffenc = ffenc->next;
    }
    q += sprintf(q, "</TABLE>\n");

    /* exclude the stat connection */
    q += sprintf(q, "Number of connections: %d / %d<BR>\n",
                 nb_connections, nb_max_connections);

    /* connection status */
    q += sprintf(q, "<H1>Connection Status</H1>\n");
    q += sprintf(q, "<TABLE>\n");
    q += sprintf(q, "<TR><TD>#<TD>File<TD>IP<TD>Size\n");
    c1 = first_http_ctx;
    i = 0;
    while (c1 != NULL) {
        i++;
        p = inet_ntoa(c1->from_addr.sin_addr);
        q += sprintf(q, "<TR><TD><B>%d</B><TD>%s <TD> %s <TD> %Ld\n", 
                     i, c1->stream->filename, p, c1->data_count);
        c1 = c1->next;
    }
    q += sprintf(q, "</TABLE>\n");
    
    /* date */
    ti = time(NULL);
    p = ctime(&ti);
    q += sprintf(q, "<HR>Generated at %s", p);
    q += sprintf(q, "</BODY>\n</HTML>\n");

    c->buffer_ptr = c->buffer;
    c->buffer_end = q;
}


static void http_write_packet(void *opaque, 
                              unsigned char *buf, int size)
{
    HTTPContext *c = opaque;
    if (size > IOBUFFER_MAX_SIZE)
        abort();
    memcpy(c->buffer, buf, size);
    c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + size;
}

/* this headers are used to identify a packet for a given codec */
void mk_header(PacketHeader *h, AVEncodeContext *c, int payload_size)
{
    h->codec_type = c->codec->type;
    h->codec_id = c->codec->id;
    h->bit_rate = htons(c->bit_rate / 1000);
    switch(c->codec->type) {
    case CODEC_TYPE_VIDEO:
        h->data[0] = c->rate;
        h->data[1] = c->width / 16;
        h->data[2] = c->height / 16;
        break;
    case CODEC_TYPE_AUDIO:
        h->data[0] = c->rate / 1000;
        h->data[1] = c->channels;
        h->data[2] = 0;
        break;
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -