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

📄 ffserver.c

📁 杜比AC-3编码解码器(参考程序)
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * Multiple format streaming server
 * Copyright (c) 2000,2001 Gerard Lantau.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <linux/videodev.h>
#include <linux/soundcard.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <errno.h>
#include <sys/time.h>
#include <getopt.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>

#include "mpegenc.h"

/* maximum number of simultaneous HTTP connections */
#define HTTP_MAX_CONNECTIONS 2000

enum HTTPState {
    HTTPSTATE_WAIT_REQUEST,
    HTTPSTATE_SEND_HEADER,
    HTTPSTATE_SEND_DATA_HEADER,
    HTTPSTATE_SEND_DATA,
    HTTPSTATE_SEND_DATA_TRAILER,
};

enum MasterState {
    MASTERSTATE_RECEIVE_HEADER,
    MASTERSTATE_RECEIVE_DATA,
};
    
#define IOBUFFER_MAX_SIZE 16384
#define FIFO_MAX_SIZE (1024*1024)

/* coef for exponential mean for bitrate estimation in statistics */
#define AVG_COEF 0.9

/* timeouts are in ms */
#define REQUEST_TIMEOUT (15 * 1000)
#define SYNC_TIMEOUT (10 * 1000)
#define MASTER_CONNECT_TIMEOUT (10 * 1000)

typedef struct HTTPContext {
    enum HTTPState state;
    int fd; /* socket file descriptor */
    struct sockaddr_in from_addr; /* origin */
    struct pollfd *poll_entry; /* used when polling */
    long timeout;
    UINT8 buffer[IOBUFFER_MAX_SIZE];
    UINT8 *buffer_ptr, *buffer_end;
    int http_error;
    struct HTTPContext *next;
    UINT8 *rptr; /* read pointer in the fifo */
    int got_key_frame[2]; /* for each type */
    long long data_count;
    long long last_http_fifo_write_count; /* used to monitor overflow in the fifo */
    /* format handling */
    struct FFStream *stream;
    AVFormatContext fmt_ctx;
    int last_packet_sent; /* true if last data packet was sent */
} HTTPContext;

/* each generated stream is described here */
enum StreamType {
    STREAM_TYPE_LIVE,
    STREAM_TYPE_MASTER,
    STREAM_TYPE_STATUS,
};

typedef struct FFStream {
    enum StreamType stream_type;
    char filename[1024];
    AVFormat *fmt;
    AVEncodeContext *audio_enc;
    AVEncodeContext *video_enc;
    struct FFStream *next;
} FFStream;

typedef struct FifoBuffer {
    UINT8 *buffer;
    UINT8 *rptr, *wptr, *end;
} FifoBuffer;

/* each codec is here */
typedef struct FFCodec {
    struct FFCodec *next;
    FifoBuffer fifo;     /* for compression: one audio fifo per codec */
    ReSampleContext resample; /* for audio resampling */
    long long data_count;
    float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
    AVEncodeContext enc;
} FFCodec;

/* packet header */
typedef struct {
    UINT8 codec_type;
    UINT8 codec_id;
    UINT8 data[4];
    UINT16 bit_rate;
    UINT16 payload_size;
} PacketHeader;

struct sockaddr_in my_addr;
char logfilename[1024];
HTTPContext *first_http_ctx;
FFStream *first_stream;
FFCodec *first_codec;

/* master state */
char master_url[1024];
enum MasterState master_state;
UINT8 *master_wptr;
int master_count;

long long http_fifo_write_count;
static FifoBuffer http_fifo;

static int handle_http(HTTPContext *c, long cur_time);
static int http_parse_request(HTTPContext *c);
static int http_send_data(HTTPContext *c);
static int master_receive(int fd);
static void compute_stats(HTTPContext *c);

int nb_max_connections;
int nb_connections;

/* fifo handling */
int fifo_init(FifoBuffer *f, int size)
{
    f->buffer = malloc(size);
    if (!f->buffer)
        return -1;
    f->end = f->buffer + size;
    f->wptr = f->rptr = f->buffer;
    return 0;
}

static int fifo_size(FifoBuffer *f, UINT8 *rptr)
{
    int size;

    if (f->wptr >= rptr) {
        size = f->wptr - rptr;
    } else {
        size = (f->end - rptr) + (f->wptr - f->buffer);
    }
    return size;
}

/* get data from the fifo (return -1 if not enough data) */
static int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr)
{
    UINT8 *rptr = *rptr_ptr;
    int size, len;

    if (f->wptr >= rptr) {
        size = f->wptr - rptr;
    } else {
        size = (f->end - rptr) + (f->wptr - f->buffer);
    }
    
    if (size < buf_size)
        return -1;
    while (buf_size > 0) {
        len = f->end - rptr;
        if (len > buf_size)
            len = buf_size;
        memcpy(buf, rptr, len);
        buf += len;
        rptr += len;
        if (rptr >= f->end)
            rptr = f->buffer;
        buf_size -= len;
    }
    *rptr_ptr = rptr;
    return 0;
}

static void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr)
{
    int len;
    UINT8 *wptr;
    wptr = *wptr_ptr;
    while (size > 0) {
        len = f->end - wptr;
        if (len > size)
            len = size;
        memcpy(wptr, buf, len);
        wptr += len;
        if (wptr >= f->end)
            wptr = f->buffer;
        buf += len;
        size -= len;
    }
    *wptr_ptr = wptr;
}

static long gettime_ms(void)
{
    struct timeval tv;

    gettimeofday(&tv,NULL);
    return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
}

static FILE *logfile = NULL;

static void http_log(char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    
    if (logfile)
        vfprintf(logfile, fmt, ap);
    va_end(ap);
}


/* connect to url 'url' and return the connected socket ready to read data */
static int url_get(const char *url)
{
    struct sockaddr_in dest_addr;
    struct hostent *h;
    int s, port, size, line_size, len;
    char hostname[1024], *q;
    const char *p, *path;
    char req[1024];
    unsigned char ch;

    if (!strstart(url, "http://", &p))
        return -1;
    q = hostname;
    while (*p != ':' && *p != '\0' && *p != '/') {
        if ((q - hostname) < (sizeof(hostname) - 1))
            *q++ = *p;
        p++;
    }
    port = 80;
    if (*p == ':') {
        p++;
        port = strtol(p, (char **)&p, 10);
    }
    path = p;
        
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(port);

    if (!inet_aton(hostname, &dest_addr.sin_addr)) {
	if ((h = gethostbyname(hostname)) == NULL)
	    return -1;
	memcpy(&dest_addr.sin_addr, h->h_addr, sizeof(dest_addr.sin_addr));
    }

    s=socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) 
        return -1;

    if (connect(s, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0) {
    fail:
	close(s);
	return -1;
    }
    
    /* send http request */
    snprintf(req, sizeof(req), "GET %s HTTP/1.0\r\n\r\n", path);
    p = req;
    size = strlen(req);
    while (size > 0) {
        len = write(s, p, size);
        if (len == -1) {
            if (errno != EAGAIN && errno != EINTR)
                goto fail;
        } else {
            size -= len;
            p += len;
        }
    }
    
    /* receive answer */
    line_size = 0;
    for(;;) {
        len = read(s, &ch, 1);
        if (len == -1) {
            if (errno != EAGAIN && errno != EINTR)
                goto fail;
        } else if (len == 0) {
            goto fail;
        } else {
            if (ch == '\n') {
                if (line_size == 0)
                    break;
                line_size = 0;
            } else if (ch != '\r') {
                line_size++;
            }
        }
    }

    return s;
}

/* Each request is served by reading the input FIFO and by adding the
   right format headers */
static int http_server(struct sockaddr_in my_addr)
{
    int server_fd, tmp, ret;
    struct sockaddr_in from_addr;
    struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 1], *poll_entry;
    HTTPContext *c, **cp;
    long cur_time;
    int master_fd, master_timeout;

    /* will try to connect to master as soon as possible */
    master_fd = -1;
    master_timeout = gettime_ms();

    server_fd = socket(AF_INET,SOCK_STREAM,0);
    if (server_fd < 0) {
        perror ("socket");
        return -1;
    }
        
    tmp = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));

    if (bind (server_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0) {
        perror ("bind");
        close(server_fd);
        return -1;
    }
  
    if (listen (server_fd, 5) < 0) {
        perror ("listen");
        close(server_fd);
        return -1;
    }

    http_log("ffserver started.\n");

    fcntl(server_fd, F_SETFL, O_NONBLOCK);
    first_http_ctx = NULL;
    nb_connections = 0;
    first_http_ctx = NULL;
    for(;;) {
        poll_entry = poll_table;
        poll_entry->fd = server_fd;
        poll_entry->events = POLLIN;
        poll_entry++;

        if (master_fd >= 0) {
            poll_entry->fd = master_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
        }

        /* wait for events on each HTTP handle */
        c = first_http_ctx;
        while (c != NULL) {
            int fd;
            fd = c->fd;
            switch(c->state) {
            case HTTPSTATE_WAIT_REQUEST:
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
                poll_entry->events = POLLIN;
                poll_entry++;
                break;
            case HTTPSTATE_SEND_HEADER:
            case HTTPSTATE_SEND_DATA_HEADER:
            case HTTPSTATE_SEND_DATA:
            case HTTPSTATE_SEND_DATA_TRAILER:
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
                poll_entry->events = POLLOUT;
                poll_entry++;
                break;
            default:
                c->poll_entry = NULL;
                break;
            }
            c = c->next;
        }

        /* wait for an event on one connection. We poll at least every
           second to handle timeouts */
        do {
            ret = poll(poll_table, poll_entry - poll_table, 1000);

⌨️ 快捷键说明

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