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

📄 ffserver.c

📁 杜比AC-3编码解码器(参考程序)
💻 C
📖 第 1 页 / 共 4 页
字号:
    h->data[3] = c->key_frame;
    h->payload_size = htons(payload_size);
}

int test_header(PacketHeader *h, AVEncodeContext *c)
{
    if (!c)
        return 0;

    if (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:
            if (h->data[0] == c->rate &&
                h->data[1] == (c->width / 16) &&
                h->data[2] == (c->height / 16))
                goto found;
            break;
        case CODEC_TYPE_AUDIO:
            if (h->data[0] == (c->rate / 1000) &&
                (h->data[1] == c->channels))
                goto found;
            break;
        }
    }
    return 0;
 found:
    c->frame_number++;
    c->key_frame = h->data[3];
    return 1;
}

static int http_prepare_data(HTTPContext *c)
{
    PacketHeader hdr;
    UINT8 *start_rptr, *payload;
    int payload_size, ret;
    long long fifo_total_size;

    switch(c->state) {
    case HTTPSTATE_SEND_DATA_HEADER:
        if (c->stream->stream_type != STREAM_TYPE_MASTER) {            
            memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
            c->fmt_ctx.format = c->stream->fmt;
            if (c->fmt_ctx.format->audio_codec != CODEC_ID_NONE) {
                /* create a fake new codec instance */
                c->fmt_ctx.audio_enc = malloc(sizeof(AVEncodeContext));
                memcpy(c->fmt_ctx.audio_enc, c->stream->audio_enc, 
                       sizeof(AVEncodeContext));
                c->fmt_ctx.audio_enc->frame_number = 0;
            }
            if (c->fmt_ctx.format->video_codec != CODEC_ID_NONE) {
                c->fmt_ctx.video_enc = malloc(sizeof(AVEncodeContext));
                memcpy(c->fmt_ctx.video_enc, c->stream->video_enc, 
                       sizeof(AVEncodeContext));
                c->fmt_ctx.video_enc->frame_number = 0;
            }
            init_put_byte(&c->fmt_ctx.pb, c->buffer, IOBUFFER_MAX_SIZE,
                          c, http_write_packet, NULL);
            c->fmt_ctx.is_streamed = 1;
            c->got_key_frame[0] = 0;
            c->got_key_frame[1] = 0;
            /* prepare header */
            c->fmt_ctx.format->write_header(&c->fmt_ctx);
        }
        c->state = HTTPSTATE_SEND_DATA;
        c->last_packet_sent = 0;
        c->rptr = http_fifo.wptr;
        c->last_http_fifo_write_count = http_fifo_write_count;
        break;
    case HTTPSTATE_SEND_DATA:
        /* find a new packet */
        fifo_total_size = http_fifo_write_count - c->last_http_fifo_write_count;
        if (fifo_total_size >= ((3 * FIFO_MAX_SIZE) / 4)) {
            /* overflow : resync. We suppose that wptr is at this
               point a pointer to a valid packet */
            c->rptr = http_fifo.wptr;
            c->got_key_frame[0] = 0;
            c->got_key_frame[1] = 0;
        }
        
        start_rptr = c->rptr;
        if (fifo_read(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &c->rptr) < 0)
            return 0;
        payload_size = ntohs(hdr.payload_size);
        payload = malloc(payload_size);
        if (fifo_read(&http_fifo, payload, payload_size, &c->rptr) < 0) {
            /* cannot read all the payload */
            free(payload);
            c->rptr = start_rptr;
            return 0;
        }
        
        c->last_http_fifo_write_count = http_fifo_write_count - 
            fifo_size(&http_fifo, c->rptr);
        
        if (c->stream->stream_type != STREAM_TYPE_MASTER) {
            /* test if the packet can be handled by this format */
            ret = 0;
            if (test_header(&hdr, c->fmt_ctx.audio_enc)) {
                /* only begin sending when got a key frame */
                if (c->fmt_ctx.audio_enc->key_frame)
                    c->got_key_frame[1] = 1;
                if (c->got_key_frame[1]) {
                    ret = c->fmt_ctx.format->write_audio_frame(&c->fmt_ctx, 
                                                               payload, payload_size);
                }
            } else if (test_header(&hdr, c->fmt_ctx.video_enc)) {
                if (c->fmt_ctx.video_enc->key_frame)
                    c->got_key_frame[0] = 1;
                if (c->got_key_frame[0]) {
                    ret = c->fmt_ctx.format->write_video_picture(&c->fmt_ctx, 
                                                                 payload, payload_size);
                }
            }
            if (ret) {
                /* must send trailer now */
                c->state = HTTPSTATE_SEND_DATA_TRAILER;
            }
        } else {
            /* master case : send everything */
            char *q;
            q = c->buffer;
            memcpy(q, &hdr, sizeof(hdr));
            q += sizeof(hdr);
            memcpy(q, payload, payload_size);
            q += payload_size;
            c->buffer_ptr = c->buffer;
            c->buffer_end = q;
        }
        free(payload);
        break;
    default:
    case HTTPSTATE_SEND_DATA_TRAILER:
        /* last packet test ? */
        if (c->last_packet_sent)
            return -1;
        /* prepare header */
        c->fmt_ctx.format->write_trailer(&c->fmt_ctx);
        c->last_packet_sent = 1;
        break;
    }
    return 0;
}


/* should convert the format at the same time */
static int http_send_data(HTTPContext *c)
{
    int len;

    while (c->buffer_ptr >= c->buffer_end) {
        if (http_prepare_data(c) < 0)
            return -1;
    }

    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;
        c->data_count += len;
    }
    return 0;
}

static int master_receive(int fd)
{
    int len, size;
    FifoBuffer *f = &http_fifo;
    UINT8 *rptr;

    size = f->end - f->wptr;
    if (size > master_count)
        size = master_count;
    len = read(fd, f->wptr, size);
    if (len == -1) {
        if (errno != EAGAIN && errno != EINTR) 
            return -1;
    } else if (len == 0) {
        return -1;
    } else {
        master_wptr += len;
        if (master_wptr >= f->end)
            master_wptr = f->buffer;
        master_count -= len;
        if (master_count == 0) {
            if (master_state == MASTERSTATE_RECEIVE_HEADER) {
                /* XXX: use generic fifo read to extract packet header */
                rptr = master_wptr;
                if (rptr == f->buffer)
                    rptr = f->end - 1;
                else
                    rptr--;
                master_count = *rptr;
                if (rptr == f->buffer)
                    rptr = f->end - 1;
                else
                    rptr--;
                master_count |= *rptr << 8;
                master_state = MASTERSTATE_RECEIVE_DATA;
            } else {
                /* update fifo wptr */
                f->wptr = master_wptr;
                master_state = MASTERSTATE_RECEIVE_HEADER;
            }
        }
    }
    return 0;
}

static void get_arg(char *buf, int buf_size, const char **pp)
{
    const char *p;
    char *q;

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

/* add a codec and check if it does not already exists */
AVEncodeContext *add_codec(int codec_id,
                           AVEncodeContext *av)
{
    AVEncoder *codec;
    FFCodec *ctx, **pctx;
    AVEncodeContext *av1;

    codec = avencoder_find(codec_id);
    if (!codec)
        return NULL;

    /* compute default parameters */
    av->codec = codec;
    switch(codec->type) {
    case CODEC_TYPE_AUDIO:
        if (av->bit_rate == 0)
            av->bit_rate = 64000;
        if (av->rate == 0)
            av->rate = 22050;
        if (av->channels == 0)
            av->channels = 1;
        break;
    case CODEC_TYPE_VIDEO:
        if (av->bit_rate == 0)
            av->bit_rate = 64000;
        if (av->rate == 0)
            av->rate = 5;
        if (av->width == 0 || av->height == 0) {
            av->width = 160;
            av->height = 128;
        }
        break;
    }

    /* find if the codec already exists */
    pctx = &first_codec;
    while (*pctx != NULL) {
        av1 = &(*pctx)->enc;
        if (av1->codec == av->codec &&
            av1->bit_rate == av->bit_rate &&
            av1->rate == av->rate) {

            switch(av->codec->type) {
            case CODEC_TYPE_AUDIO:
                if (av1->channels == av->channels)
                    goto found;
                break;
            case CODEC_TYPE_VIDEO:
                if (av1->width == av->width &&
                    av1->height == av->height &&
                    av1->gop_size == av->gop_size)
                    goto found;
                break;
            }
        }
        pctx = &(*pctx)->next;
    }

    ctx = malloc(sizeof(FFCodec));
    if (!ctx)
        return NULL;
    memset(ctx, 0, sizeof(FFCodec));
    *pctx = ctx;
    
    memcpy(&ctx->enc, av, sizeof(AVEncodeContext));
    return &ctx->enc;
 found:
    ctx = *pctx;
    return &ctx->enc;
}

int parse_ffconfig(const char *filename)
{
    FILE *f;
    char line[1024];
    char cmd[64];
    char arg[1024];
    const char *p;
    int val, errors, line_num;
    FFStream **last_stream, *stream;
    AVEncodeContext audio_enc, video_enc;

    f = fopen(filename, "r");
    if (!f) {
        perror(filename);
        return -1;
    }
    
    errors = 0;
    line_num = 0;
    first_stream = NULL;
    first_codec = NULL;
    last_stream = &first_stream;
    stream = NULL;
    for(;;) {
        if (fgets(line, sizeof(line), f) == NULL)
            break;
        line_num++;
        p = line;
        while (isspace(*p)) 
            p++;
        if (*p == '\0' || *p == '#')
            continue;

        get_arg(cmd, sizeof(cmd), &p);
        
        if (!strcasecmp(cmd, "Port")) {
            get_arg(arg, sizeof(arg), &p);
            my_addr.sin_port = htons (atoi(arg));
        } else if (!strcasecmp(cmd, "BindAddress")) {
            get_arg(arg, sizeof(arg), &p);
            if (!inet_aton(arg, &my_addr.sin_addr)) {
                fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
                        filename, line_num, arg);
                errors++;
            }
        } else if (!strcasecmp(cmd, "MasterServer")) {
            get_arg(master_url, sizeof(master_url), &p);
            if (!strstart(master_url, "http://", NULL)) {
                fprintf(stderr, "%s:%d: Invalid URL for master server: %s\n", 
                        filename, line_num, master_url);
                errors++;
            }
        } else if (!strcasecmp(cmd, "AudioDevice")) {
            get_arg(arg, sizeof(arg), &p);
            audio_device = strdup(arg);
        } else if (!strcasecmp(cmd, "VideoDevice")) {
            get_arg(arg, sizeof(arg), &p);
            v4l_device = strdup(arg);
        } else if (!strcasecmp(cmd, "MaxClients")) {
            get_arg(arg, sizeof(arg), &p);
            val = atoi(arg);
            if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
                        filename, line_num, arg);
                errors++;
            } else {
                nb_max_connections = val;
            }
        } else if (!strcasecmp(cmd, "CustomLog")) {
            get_arg(logfilename, sizeof(logfilename), &p);
        } else if (!strcasecmp(cmd, "<Stream")) {
            char *q;
            if (stream) {
                fprintf(stderr, "%s:%d: Already in a stream tag\n",
                        filename, line_num);
            } else {
                stream = malloc(sizeof(FFStream));
                memset(stream, 0, sizeof(FFStream));
                *last_stream = stream;
                last_stream = &stream->next;

                get_arg(stream->filename, sizeof(stream->filename), &p);
                q = strrchr(stream->filename, '>');
                if (*q)
                    *q = '\0';
                stream->fmt = guess_format(NULL, stream->filename, NULL);
                memset(&audio_enc, 0, sizeof(AVEncodeContext));
                memset(&video_enc, 0, sizeof(AVEncodeContext));
            }
        } else if (!strcasecmp(cmd, "Format")) {
            get_arg(arg, sizeof(arg), &p);
            if (!strcmp(arg, "master")) {
                stream->stream_type = STREAM_TYPE_MASTER;
                stream->fmt = NULL;
            } else if (!strcmp(arg, "status")) {
                stream->stream_type = STREAM_TYPE_STATUS;
                stream->fmt = NULL;
            } else {
                stream->stream_type = STREAM_TYPE_LIVE;
                stream->fmt = guess_format(arg, NULL, NULL);
                if (!stream->fmt) {
                    fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
                            filename, line_num, arg);
                    errors++;
                }
            }
        } else if (!strcasecmp(cmd, "AudioBitRate")) {
            get_arg(arg, sizeof(arg), &p);
            if (stream) {

⌨️ 快捷键说明

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