static 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, *redirect;

    FFStream **last_feed, *feed, *s;

    AVCodecContext audio_enc, video_enc;

    enum CodecID audio_id, video_id;

    f = fopen(filename, "r");

    if (!f) {

        perror(filename);

        return -1;

    }

    errors = 0;

    line_num = 0;

    first_stream = NULL;

    last_stream = &first_stream;

    first_feed = NULL;

    last_feed = &first_feed;

    stream = NULL;

    feed = NULL;

    redirect = NULL;

    audio_id = CODEC_ID_NONE;

    video_id = CODEC_ID_NONE;

    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);

            val = atoi(arg);

            if (val < 1 || val > 65536) {

                fprintf(stderr, "%s:%d: Invalid port: %s\n",

                        filename, line_num, arg);

                errors++;

            }

            my_http_addr.sin_port = htons(val);

        } else if (!strcasecmp(cmd, "BindAddress")) {

            get_arg(arg, sizeof(arg), &p);

            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {

                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",

                        filename, line_num, arg);

                errors++;

            }

        } else if (!strcasecmp(cmd, "NoDaemon")) {

            ffserver_daemon = 0;

        } else if (!strcasecmp(cmd, "RTSPPort")) {

            get_arg(arg, sizeof(arg), &p);

            val = atoi(arg);

            if (val < 1 || val > 65536) {

                fprintf(stderr, "%s:%d: Invalid port: %s\n",

                        filename, line_num, arg);

                errors++;

            }

            my_rtsp_addr.sin_port = htons(atoi(arg));

        } else if (!strcasecmp(cmd, "RTSPBindAddress")) {

            get_arg(arg, sizeof(arg), &p);

            if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {

                fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",

                        filename, line_num, arg);

                errors++;

            }

        } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {

            get_arg(arg, sizeof(arg), &p);

            val = atoi(arg);

            if (val < 1 || val > 65536) {

                fprintf(stderr, "%s:%d: Invalid MaxHTTPConnections: %s\n",

                        filename, line_num, arg);

                errors++;

            }

            nb_max_http_connections = val;

        } else if (!strcasecmp(cmd, "MaxClients")) {

            get_arg(arg, sizeof(arg), &p);

            val = atoi(arg);

            if (val < 1 || val > nb_max_http_connections) {

                fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n",

                        filename, line_num, arg);

                errors++;

            } else {

                nb_max_connections = val;

            }

        } else if (!strcasecmp(cmd, "MaxBandwidth")) {

            int64_t llval;

            get_arg(arg, sizeof(arg), &p);

            llval = atoll(arg);

            if (llval < 10 || llval > 10000000) {

                fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n",

                        filename, line_num, arg);

                errors++;

            } else

                max_bandwidth = llval;

        } else if (!strcasecmp(cmd, "CustomLog")) {

            if (!ffserver_debug)

                get_arg(logfilename, sizeof(logfilename), &p);

        } else if (!strcasecmp(cmd, "<Feed")) {

            /*********************************************/

            /* Feed related options */

            char *q;

            if (stream || feed) {

                fprintf(stderr, "%s:%d: Already in a tag\n",

                        filename, line_num);

            } else {

                feed = av_mallocz(sizeof(FFStream));

                get_arg(feed->filename, sizeof(feed->filename), &p);

                q = strrchr(feed->filename, '>');

                if (*q)

                    *q = '\0';

                for (s = first_feed; s; s = s->next) {

                    if (!strcmp(feed->filename, s->filename)) {

                        fprintf(stderr, "%s:%d: Feed '%s' already registered\n",

                                filename, line_num, s->filename);

                        errors++;

                    }

                }

                feed->fmt = guess_format("ffm", NULL, NULL);

                /* defaut feed file */

                snprintf(feed->feed_filename, sizeof(feed->feed_filename),

                         "/tmp/%s.ffm", feed->filename);

                feed->feed_max_size = 5 * 1024 * 1024;

                feed->is_feed = 1;

                feed->feed = feed; /* self feeding :-) */

                /* add in stream list */

                *last_stream = feed;

                last_stream = &feed->next;

                /* add in feed list */

                *last_feed = feed;

                last_feed = &feed->next_feed;

            }

        } else if (!strcasecmp(cmd, "Launch")) {

            if (feed) {

                int i;

                feed->child_argv = av_mallocz(64 * sizeof(char *));

                for (i = 0; i < 62; i++) {

                    get_arg(arg, sizeof(arg), &p);

                    if (!arg[0])

                        break;

                    feed->child_argv[i] = av_strdup(arg);

                }

                feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));

                snprintf(feed->child_argv[i], 30+strlen(feed->filename),

                    "http://%s:%d/%s",

                        (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :

                    inet_ntoa(my_http_addr.sin_addr),

                    ntohs(my_http_addr.sin_port), feed->filename);

            }

        } else if (!strcasecmp(cmd, "ReadOnlyFile")) {

            if (feed) {

                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);

                feed->readonly = 1;

            } else if (stream) {

                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);

            }

        } else if (!strcasecmp(cmd, "File")) {

            if (feed) {

                get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);

            } else if (stream)

                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);

        } else if (!strcasecmp(cmd, "Truncate")) {

            if (feed) {

                get_arg(arg, sizeof(arg), &p);

                feed->truncate = strtod(arg, NULL);

            }

        } else if (!strcasecmp(cmd, "FileMaxSize")) {

            if (feed) {

                char *p1;

                double fsize;

                get_arg(arg, sizeof(arg), &p);

                p1 = arg;

                fsize = strtod(p1, &p1);

                switch(toupper(*p1)) {

                case 'K':

                    fsize *= 1024;

                    break;

                case 'M':

                    fsize *= 1024 * 1024;

                    break;

                case 'G':

                    fsize *= 1024 * 1024 * 1024;

                    break;

                }

                feed->feed_max_size = (int64_t)fsize;

                if (feed->feed_max_size < FFM_PACKET_SIZE*4) {

                    fprintf(stderr, "%s:%d: Feed max file size is too small, "

                            "must be at least %d\n", filename, line_num, FFM_PACKET_SIZE*4);

                    errors++;

                }

            }

        } else if (!strcasecmp(cmd, "</Feed>")) {

            if (!feed) {

                fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",

                        filename, line_num);

                errors++;

            }

            feed = NULL;

        } else if (!strcasecmp(cmd, "<Stream")) {

            /*********************************************/

            /* Stream related options */

            char *q;

            if (stream || feed) {

                fprintf(stderr, "%s:%d: Already in a tag\n",

                        filename, line_num);

            } else {

                FFStream *s;

                const AVClass *class;

                stream = av_mallocz(sizeof(FFStream));

                get_arg(stream->filename, sizeof(stream->filename), &p);

                q = strrchr(stream->filename, '>');

                if (*q)

                    *q = '\0';

                for (s = first_stream; s; s = s->next) {

                    if (!strcmp(stream->filename, s->filename)) {

                        fprintf(stderr, "%s:%d: Stream '%s' already registered\n",

                                filename, line_num, s->filename);

                        errors++;

                    }

                }

                stream->fmt = guess_stream_format(NULL, stream->filename, NULL);

                /* fetch avclass so AVOption works

                 * FIXME try to use avcodec_get_context_defaults2

                 * without changing defaults too much */

                avcodec_get_context_defaults(&video_enc);

                class = video_enc.av_class;

                memset(&audio_enc, 0, sizeof(AVCodecContext));

                memset(&video_enc, 0, sizeof(AVCodecContext));

                audio_enc.av_class = class;

                video_enc.av_class = class;

                audio_id = CODEC_ID_NONE;

                video_id = CODEC_ID_NONE;

                if (stream->fmt) {

                    audio_id = stream->fmt->audio_codec;

                    video_id = stream->fmt->video_codec;

                }

                *last_stream = stream;

                last_stream = &stream->next;

            }

        } else if (!strcasecmp(cmd, "Feed")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                FFStream *sfeed;

                sfeed = first_feed;

                while (sfeed != NULL) {

                    if (!strcmp(sfeed->filename, arg))

                        break;

                    sfeed = sfeed->next_feed;

                }

                if (!sfeed)

                    fprintf(stderr, "%s:%d: feed '%s' not defined\n",

                            filename, line_num, arg);

                else

                    stream->feed = sfeed;

            }

        } else if (!strcasecmp(cmd, "Format")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                if (!strcmp(arg, "status")) {

                    stream->stream_type = STREAM_TYPE_STATUS;

                    stream->fmt = NULL;

                } else {

                    stream->stream_type = STREAM_TYPE_LIVE;

                    /* jpeg cannot be used here, so use single frame jpeg */

                    if (!strcmp(arg, "jpeg"))

                        strcpy(arg, "mjpeg");

                    stream->fmt = guess_stream_format(arg, NULL, NULL);

                    if (!stream->fmt) {

                        fprintf(stderr, "%s:%d: Unknown Format: %s\n",

                                filename, line_num, arg);

                        errors++;

                    }

                }

                if (stream->fmt) {

                    audio_id = stream->fmt->audio_codec;

                    video_id = stream->fmt->video_codec;

                }

            }

        } else if (!strcasecmp(cmd, "InputFormat")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                stream->ifmt = av_find_input_format(arg);

                if (!stream->ifmt) {

                    fprintf(stderr, "%s:%d: Unknown input format: %s\n",

                            filename, line_num, arg);

                }

            }

        } else if (!strcasecmp(cmd, "FaviconURL")) {

            if (stream && stream->stream_type == STREAM_TYPE_STATUS) {

                get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);

            } else {

                fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n",

                            filename, line_num);

                errors++;

            }

        } else if (!strcasecmp(cmd, "Author")) {

            if (stream)

                get_arg(stream->author, sizeof(stream->author), &p);

        } else if (!strcasecmp(cmd, "Comment")) {

            if (stream)

                get_arg(stream->comment, sizeof(stream->comment), &p);

        } else if (!strcasecmp(cmd, "Copyright")) {

            if (stream)

                get_arg(stream->copyright, sizeof(stream->copyright), &p);

        } else if (!strcasecmp(cmd, "Title")) {

            if (stream)

                get_arg(stream->title, sizeof(stream->title), &p);

        } else if (!strcasecmp(cmd, "Preroll")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                stream->prebuffer = atof(arg) * 1000;

        } else if (!strcasecmp(cmd, "StartSendOnKey")) {

            if (stream)

                stream->send_on_key = 1;

        } else if (!strcasecmp(cmd, "AudioCodec")) {

            get_arg(arg, sizeof(arg), &p);

            audio_id = opt_audio_codec(arg);

            if (audio_id == CODEC_ID_NONE) {

                fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n",

                        filename, line_num, arg);

                errors++;

            }

        } else if (!strcasecmp(cmd, "VideoCodec")) {

            get_arg(arg, sizeof(arg), &p);

            video_id = opt_video_codec(arg);

            if (video_id == CODEC_ID_NONE) {

                fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n",

                        filename, line_num, arg);

                errors++;

            }

        } else if (!strcasecmp(cmd, "MaxTime")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                stream->max_time = atof(arg) * 1000;

        } else if (!strcasecmp(cmd, "AudioBitRate")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                audio_enc.bit_rate = atoi(arg) * 1000;

        } else if (!strcasecmp(cmd, "AudioChannels")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                audio_enc.channels = atoi(arg);

        } else if (!strcasecmp(cmd, "AudioSampleRate")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                audio_enc.sample_rate = atoi(arg);

        } else if (!strcasecmp(cmd, "AudioQuality")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

//                audio_enc.quality = atof(arg) * 1000;

            }

        } else if (!strcasecmp(cmd, "VideoBitRateRange")) {

            if (stream) {

                int minrate, maxrate;

                get_arg(arg, sizeof(arg), &p);

                if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {

                    video_enc.rc_min_rate = minrate * 1000;

                    video_enc.rc_max_rate = maxrate * 1000;

                } else {

                    fprintf(stderr, "%s:%d: Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n",

                            filename, line_num, arg);

                    errors++;

                }

            }

        } else if (!strcasecmp(cmd, "Debug")) {

            if (stream) {

                get_arg(arg, sizeof(arg), &p);

                video_enc.debug = strtol(arg,0,0);

            }

        } else if (!strcasecmp(cmd, "Strict")) {

            if (stream) {

                get_arg(arg, sizeof(arg), &p);

                video_enc.strict_std_compliance = atoi(arg);

            }

        } else if (!strcasecmp(cmd, "VideoBufferSize")) {

            if (stream) {

                get_arg(arg, sizeof(arg), &p);

                video_enc.rc_buffer_size = atoi(arg) * 8*1024;

            }

        } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {

            if (stream) {

                get_arg(arg, sizeof(arg), &p);

                video_enc.bit_rate_tolerance = atoi(arg) * 1000;

            }

        } else if (!strcasecmp(cmd, "VideoBitRate")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                video_enc.bit_rate = atoi(arg) * 1000;

            }

        } else if (!strcasecmp(cmd, "VideoSize")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                av_parse_video_frame_size(&video_enc.width, &video_enc.height, arg);

                if ((video_enc.width % 16) != 0 ||

                    (video_enc.height % 16) != 0) {

                    fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",

                            filename, line_num);

                    errors++;

                }

            }

        } else if (!strcasecmp(cmd, "VideoFrameRate")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                AVRational frame_rate;

                if (av_parse_video_frame_rate(&frame_rate, arg) < 0) {

                    fprintf(stderr, "Incorrect frame rate\n");

                    errors++;

                } else {

                    video_enc.time_base.num = frame_rate.den;

                    video_enc.time_base.den = frame_rate.num;

                }

            }

        } else if (!strcasecmp(cmd, "VideoGopSize")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                video_enc.gop_size = atoi(arg);

        } else if (!strcasecmp(cmd, "VideoIntraOnly")) {

            if (stream)

                video_enc.gop_size = 1;

        } else if (!strcasecmp(cmd, "VideoHighQuality")) {

            if (stream)

                video_enc.mb_decision = FF_MB_DECISION_BITS;

        } else if (!strcasecmp(cmd, "Video4MotionVector")) {

            if (stream) {

                video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove

                video_enc.flags |= CODEC_FLAG_4MV;

            }

        } else if (!strcasecmp(cmd, "AVOptionVideo") ||

                   !strcasecmp(cmd, "AVOptionAudio")) {

            char arg2[1024];

            AVCodecContext *avctx;

            int type;

            get_arg(arg, sizeof(arg), &p);

            get_arg(arg2, sizeof(arg2), &p);

            if (!strcasecmp(cmd, "AVOptionVideo")) {

                avctx = &video_enc;

                type = AV_OPT_FLAG_VIDEO_PARAM;

            } else {

                avctx = &audio_enc;

                type = AV_OPT_FLAG_AUDIO_PARAM;

            }

            if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {

                fprintf(stderr, "AVOption error: %s %s\n", arg, arg2);

                errors++;

            }

        } else if (!strcasecmp(cmd, "VideoTag")) {

            get_arg(arg, sizeof(arg), &p);

            if ((strlen(arg) == 4) && stream)

                video_enc.codec_tag = AV_RL32(arg);

        } else if (!strcasecmp(cmd, "BitExact")) {

            if (stream)

                video_enc.flags |= CODEC_FLAG_BITEXACT;

        } else if (!strcasecmp(cmd, "DctFastint")) {

            if (stream)

                video_enc.dct_algo  = FF_DCT_FASTINT;

        } else if (!strcasecmp(cmd, "IdctSimple")) {

            if (stream)

                video_enc.idct_algo = FF_IDCT_SIMPLE;

        } else if (!strcasecmp(cmd, "Qscale")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                video_enc.flags |= CODEC_FLAG_QSCALE;

                video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);

            }

        } else if (!strcasecmp(cmd, "VideoQDiff")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                video_enc.max_qdiff = atoi(arg);

                if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {

                    fprintf(stderr, "%s:%d: VideoQDiff out of range\n",

                            filename, line_num);

                    errors++;

                }

            }

        } else if (!strcasecmp(cmd, "VideoQMax")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                video_enc.qmax = atoi(arg);

                if (video_enc.qmax < 1 || video_enc.qmax > 31) {

                    fprintf(stderr, "%s:%d: VideoQMax out of range\n",

                            filename, line_num);

                    errors++;

                }

            }

        } else if (!strcasecmp(cmd, "VideoQMin")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                video_enc.qmin = atoi(arg);

                if (video_enc.qmin < 1 || video_enc.qmin > 31) {

                    fprintf(stderr, "%s:%d: VideoQMin out of range\n",

                            filename, line_num);

                    errors++;

                }

            }

        } else if (!strcasecmp(cmd, "LumaElim")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                video_enc.luma_elim_threshold = atoi(arg);

        } else if (!strcasecmp(cmd, "ChromaElim")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                video_enc.chroma_elim_threshold = atoi(arg);

        } else if (!strcasecmp(cmd, "LumiMask")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                video_enc.lumi_masking = atof(arg);

        } else if (!strcasecmp(cmd, "DarkMask")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                video_enc.dark_masking = atof(arg);

        } else if (!strcasecmp(cmd, "NoVideo")) {

            video_id = CODEC_ID_NONE;

        } else if (!strcasecmp(cmd, "NoAudio")) {

            audio_id = CODEC_ID_NONE;

        } else if (!strcasecmp(cmd, "ACL")) {

            IPAddressACL acl;

            get_arg(arg, sizeof(arg), &p);

            if (strcasecmp(arg, "allow") == 0)

                acl.action = IP_ALLOW;

            else if (strcasecmp(arg, "deny") == 0)

                acl.action = IP_DENY;

            else {

                fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",

                        filename, line_num, arg);

                errors++;

            }

            get_arg(arg, sizeof(arg), &p);

            if (resolve_host(&acl.first, arg) != 0) {

                fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",

                        filename, line_num, arg);

                errors++;

            } else

                acl.last = acl.first;

            get_arg(arg, sizeof(arg), &p);

            if (arg[0]) {

                if (resolve_host(&acl.last, arg) != 0) {

                    fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",

                            filename, line_num, arg);

                    errors++;

                }

            }

            if (!errors) {

                IPAddressACL *nacl = av_mallocz(sizeof(*nacl));

                IPAddressACL **naclp = 0;

                acl.next = 0;

                *nacl = acl;

                if (stream)

                    naclp = &stream->acl;

                else if (feed)

                    naclp = &feed->acl;

                else {

                    fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",

                            filename, line_num);

                    errors++;

                }

                if (naclp) {

                    while (*naclp)

                        naclp = &(*naclp)->next;

                    *naclp = nacl;

                }

            }

        } else if (!strcasecmp(cmd, "RTSPOption")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                av_freep(&stream->rtsp_option);

                stream->rtsp_option = av_strdup(arg);

            }

        } else if (!strcasecmp(cmd, "MulticastAddress")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream) {

                if (resolve_host(&stream->multicast_ip, arg) != 0) {

                    fprintf(stderr, "%s:%d: Invalid host/IP address: %s\n",

                            filename, line_num, arg);

                    errors++;

                }

                stream->is_multicast = 1;

                stream->loop = 1; /* default is looping */

            }

        } else if (!strcasecmp(cmd, "MulticastPort")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                stream->multicast_port = atoi(arg);

        } else if (!strcasecmp(cmd, "MulticastTTL")) {

            get_arg(arg, sizeof(arg), &p);

            if (stream)

                stream->multicast_ttl = atoi(arg);

        } else if (!strcasecmp(cmd, "NoLoop")) {

            if (stream)

                stream->loop = 0;

        } else if (!strcasecmp(cmd, "</Stream>")) {

            if (!stream) {

                fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",

                        filename, line_num);

                errors++;

            } else {

                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {

                    if (audio_id != CODEC_ID_NONE) {

                        audio_enc.codec_type = CODEC_TYPE_AUDIO;

                        audio_enc.codec_id = audio_id;

                        add_codec(stream, &audio_enc);

                    }

                    if (video_id != CODEC_ID_NONE) {

                        video_enc.codec_type = CODEC_TYPE_VIDEO;

                        video_enc.codec_id = video_id;

                        add_codec(stream, &video_enc);

                    }

                }

                stream = NULL;

            }

        } else if (!strcasecmp(cmd, "<Redirect")) {

            /*********************************************/

            char *q;

            if (stream || feed || redirect) {

                fprintf(stderr, "%s:%d: Already in a tag\n",

                        filename, line_num);

                errors++;

            } else {

                redirect = av_mallocz(sizeof(FFStream));

                *last_stream = redirect;

                last_stream = &redirect->next;

                get_arg(redirect->filename, sizeof(redirect->filename), &p);

                q = strrchr(redirect->filename, '>');

                if (*q)

                    *q = '\0';

                redirect->stream_type = STREAM_TYPE_REDIRECT;

            }

        } else if (!strcasecmp(cmd, "URL")) {

            if (redirect)

                get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);

        } else if (!strcasecmp(cmd, "</Redirect>")) {

            if (!redirect) {

                fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",

                        filename, line_num);

                errors++;

            } else {

                if (!redirect->feed_filename[0]) {

                    fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",

                            filename, line_num);

                    errors++;

                }

                redirect = NULL;

            }

        } else if (!strcasecmp(cmd, "LoadModule")) {

            get_arg(arg, sizeof(arg), &p);

#if HAVE_DLOPEN

            load_module(arg);

#else

            fprintf(stderr, "%s:%d: Module support not compiled into this version: '%s'\n",

                    filename, line_num, arg);

            errors++;

#endif

        } else {

            fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n",

                    filename, line_num, cmd);

        }

    }

    fclose(f);

    if (errors)

        return -1;

    else

        return 0;

}


void ff_put_h264_qpel16_mc03_msa(uint8_t *dst, const uint8_t *src,

                                 ptrdiff_t stride)

{

    avc_luma_vt_qrt_16w_msa(src - (stride * 2), stride, dst, stride, 16, 1);

}


static int ccw_dstream_rw_noflags(CcwDataStream *cds, void *buff, int len,

                                  CcwDataStreamOp op)

{

    int ret;

    ret = cds_check_len(cds, len);

    if (ret <= 0) {

        return ret;

    if (op == CDS_OP_A) {

        goto incr;

    ret = address_space_rw(&address_space_memory, cds->cda,

                           MEMTXATTRS_UNSPECIFIED, buff, len, op);

    if (ret != MEMTX_OK) {

        cds->flags |= CDS_F_STREAM_BROKEN;

        return -EINVAL;

incr:

    cds->at_byte += len;

    cds->cda += len;

    return 0;


static void grlib_apbuart_write(void *opaque, hwaddr addr,

                                uint64_t value, unsigned size)

{

    UART          *uart = opaque;

    unsigned char  c    = 0;

    addr &= 0xff;

    /* Unit registers */

    switch (addr) {

    case DATA_OFFSET:

    case DATA_OFFSET + 3:       /* When only one byte write */

        /* Transmit when character device available and transmitter enabled */

        if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {

            c = value & 0xFF;

            qemu_chr_fe_write(uart->chr, &c, 1);

            /* Generate interrupt */

            if (uart->control & UART_TRANSMIT_INTERRUPT) {

                qemu_irq_pulse(uart->irq);

            }

        }

        return;

    case STATUS_OFFSET:

        /* Read Only */

        return;

    case CONTROL_OFFSET:

        uart->control = value;

        return;

    case SCALER_OFFSET:

        /* Not supported */

        return;

    default:

        break;

    }

    trace_grlib_apbuart_writel_unknown(addr, value);

}


static int mpeg_decode_slice(Mpeg1Context *s1, int mb_y,

                             const uint8_t **buf, int buf_size)

{

    MpegEncContext *s = &s1->mpeg_enc_ctx;

    AVCodecContext *avctx= s->avctx;

    int ret;

    const int field_pic= s->picture_structure != PICT_FRAME;

    s->resync_mb_x=

    s->resync_mb_y= -1;

    if (mb_y >= s->mb_height){

        av_log(s->avctx, AV_LOG_ERROR, "slice below image (%d >= %d)\n", s->mb_y, s->mb_height);

        return -1;

    }

    init_get_bits(&s->gb, *buf, buf_size*8);

    ff_mpeg1_clean_buffers(s);

    s->interlaced_dct = 0;

    s->qscale = get_qscale(s);

    if(s->qscale == 0){

        av_log(s->avctx, AV_LOG_ERROR, "qscale == 0\n");

        return -1;

    }

    /* extra slice info */

    while (get_bits1(&s->gb) != 0) {

        skip_bits(&s->gb, 8);

    }

    s->mb_x=0;

    for(;;) {

        int code = get_vlc2(&s->gb, mbincr_vlc.table, MBINCR_VLC_BITS, 2);

        if (code < 0){

            av_log(s->avctx, AV_LOG_ERROR, "first mb_incr damaged\n");

            return -1;

        }

        if (code >= 33) {

            if (code == 33) {

                s->mb_x += 33;

            }

            /* otherwise, stuffing, nothing to do */

        } else {

            s->mb_x += code;

            break;

        }

    }

    s->resync_mb_x= s->mb_x;

    s->resync_mb_y= s->mb_y= mb_y;

    s->mb_skip_run= 0;

    ff_init_block_index(s);

    if (s->mb_y==0 && s->mb_x==0 && (s->first_field || s->picture_structure==PICT_FRAME)) {

        if(s->avctx->debug&FF_DEBUG_PICT_INFO){

             av_log(s->avctx, AV_LOG_DEBUG, "qp:%d fc:%2d%2d%2d%2d %s %s %s %s %s dc:%d pstruct:%d fdct:%d cmv:%d qtype:%d ivlc:%d rff:%d %s\n",

                 s->qscale, s->mpeg_f_code[0][0],s->mpeg_f_code[0][1],s->mpeg_f_code[1][0],s->mpeg_f_code[1][1],

                 s->pict_type == I_TYPE ? "I" : (s->pict_type == P_TYPE ? "P" : (s->pict_type == B_TYPE ? "B" : "S")),

                 s->progressive_sequence ? "ps" :"", s->progressive_frame ? "pf" : "", s->alternate_scan ? "alt" :"", s->top_field_first ? "top" :"",

                 s->intra_dc_precision, s->picture_structure, s->frame_pred_frame_dct, s->concealment_motion_vectors,

                 s->q_scale_type, s->intra_vlc_format, s->repeat_first_field, s->chroma_420_type ? "420" :"");

        }

    }

    for(;;) {

#ifdef HAVE_XVMC

        //one 1 we memcpy blocks in xvmcvideo

        if(s->avctx->xvmc_acceleration > 1)

            XVMC_init_block(s);//set s->block

#endif

	s->dsp.clear_blocks(s->block[0]);

        ret = mpeg_decode_mb(s, s->block);

        s->chroma_qscale= s->qscale;

        dprintf("ret=%d\n", ret);

        if (ret < 0)

            return -1;

        if(s->current_picture.motion_val[0] && !s->encoding){ //note motion_val is normally NULL unless we want to extract the MVs

            const int wrap = field_pic ? 2*s->b8_stride : s->b8_stride;

            int xy = s->mb_x*2 + s->mb_y*2*wrap;

            int motion_x, motion_y, dir, i;

            if(field_pic && !s->first_field)

                xy += wrap/2;

            for(i=0; i<2; i++){

                for(dir=0; dir<2; dir++){

                    if (s->mb_intra || (dir==1 && s->pict_type != B_TYPE)) {

                        motion_x = motion_y = 0;

                    }else if (s->mv_type == MV_TYPE_16X16 || (s->mv_type == MV_TYPE_FIELD && field_pic)){

                        motion_x = s->mv[dir][0][0];

                        motion_y = s->mv[dir][0][1];

                    } else /*if ((s->mv_type == MV_TYPE_FIELD) || (s->mv_type == MV_TYPE_16X8))*/ {

                        motion_x = s->mv[dir][i][0];

                        motion_y = s->mv[dir][i][1];

                    }

                    s->current_picture.motion_val[dir][xy    ][0] = motion_x;

                    s->current_picture.motion_val[dir][xy    ][1] = motion_y;

                    s->current_picture.motion_val[dir][xy + 1][0] = motion_x;

                    s->current_picture.motion_val[dir][xy + 1][1] = motion_y;

                    s->current_picture.ref_index [dir][xy    ]=

                    s->current_picture.ref_index [dir][xy + 1]= s->field_select[dir][i];

                }

                xy += wrap;

            }

        }

        s->dest[0] += 16;

        s->dest[1] += 8;

        s->dest[2] += 8;

        MPV_decode_mb(s, s->block);

        if (++s->mb_x >= s->mb_width) {

            ff_draw_horiz_band(s, 16*s->mb_y, 16);

            s->mb_x = 0;

            s->mb_y++;

            if(s->mb_y<<field_pic >= s->mb_height){

                int left= s->gb.size_in_bits - get_bits_count(&s->gb);

                if(left < 0 || (left && show_bits(&s->gb, FFMIN(left, 23)))

                   || (avctx->error_resilience >= FF_ER_AGGRESSIVE && left>8)){

                    av_log(avctx, AV_LOG_ERROR, "end mismatch left=%d\n", left);

                    return -1;

                }else

                    goto eos;

            }

            ff_init_block_index(s);

        }

        /* skip mb handling */

        if (s->mb_skip_run == -1) {

            /* read again increment */

            s->mb_skip_run = 0;

            for(;;) {

                int code = get_vlc2(&s->gb, mbincr_vlc.table, MBINCR_VLC_BITS, 2);

                if (code < 0){

                    av_log(s->avctx, AV_LOG_ERROR, "mb incr damaged\n");

                    return -1;

                }

                if (code >= 33) {

                    if (code == 33) {

                        s->mb_skip_run += 33;

                    }else if(code == 35){

                        if(s->mb_skip_run != 0 || show_bits(&s->gb, 15) != 0){

                            av_log(s->avctx, AV_LOG_ERROR, "slice mismatch\n");

                            return -1;

                        }

                        goto eos; /* end of slice */

                    }

                    /* otherwise, stuffing, nothing to do */

                } else {

                    s->mb_skip_run += code;

                    break;

                }

            }

        }

    }

eos: // end of slice

    *buf += get_bits_count(&s->gb)/8 - 1;

//printf("y %d %d %d %d\n", s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y);

    return 0;

}


av_cold void ff_schro_queue_init(FFSchroQueue *queue)

{

    queue->p_head = queue->p_tail = NULL;

    queue->size = 0;

}


static int ffm_write_header(AVFormatContext *s)

{

    FFMContext *ffm = s->priv_data;

    AVStream *st;

    ByteIOContext *pb = s->pb;

    AVCodecContext *codec;

    int bit_rate, i;

    ffm->packet_size = FFM_PACKET_SIZE;

    /* header */

    put_le32(pb, MKTAG('F', 'F', 'M', '1'));

    put_be32(pb, ffm->packet_size);

    /* XXX: store write position in other file ? */

    put_be64(pb, ffm->packet_size); /* current write position */

    put_be32(pb, s->nb_streams);

    bit_rate = 0;

    for(i=0;i<s->nb_streams;i++) {

        st = s->streams[i];

        bit_rate += st->codec->bit_rate;

    }

    put_be32(pb, bit_rate);

    /* list of streams */

    for(i=0;i<s->nb_streams;i++) {

        st = s->streams[i];

        av_set_pts_info(st, 64, 1, 1000000);

        codec = st->codec;

        /* generic info */

        put_be32(pb, codec->codec_id);

        put_byte(pb, codec->codec_type);

        put_be32(pb, codec->bit_rate);

        put_be32(pb, st->quality);

        put_be32(pb, codec->flags);

        put_be32(pb, codec->flags2);

        put_be32(pb, codec->debug);

        /* specific info */

        switch(codec->codec_type) {

        case CODEC_TYPE_VIDEO:

            put_be32(pb, codec->time_base.num);

            put_be32(pb, codec->time_base.den);

            put_be16(pb, codec->width);

            put_be16(pb, codec->height);

            put_be16(pb, codec->gop_size);

            put_be32(pb, codec->pix_fmt);

            put_byte(pb, codec->qmin);

            put_byte(pb, codec->qmax);

            put_byte(pb, codec->max_qdiff);

            put_be16(pb, (int) (codec->qcompress * 10000.0));

            put_be16(pb, (int) (codec->qblur * 10000.0));

            put_be32(pb, codec->bit_rate_tolerance);

            put_strz(pb, codec->rc_eq);

            put_be32(pb, codec->rc_max_rate);

            put_be32(pb, codec->rc_min_rate);

            put_be32(pb, codec->rc_buffer_size);

            put_be64(pb, av_dbl2int(codec->i_quant_factor));

            put_be64(pb, av_dbl2int(codec->b_quant_factor));

            put_be64(pb, av_dbl2int(codec->i_quant_offset));

            put_be64(pb, av_dbl2int(codec->b_quant_offset));

            put_be32(pb, codec->dct_algo);

            put_be32(pb, codec->strict_std_compliance);

            put_be32(pb, codec->max_b_frames);

            put_be32(pb, codec->luma_elim_threshold);

            put_be32(pb, codec->chroma_elim_threshold);

            put_be32(pb, codec->mpeg_quant);

            put_be32(pb, codec->intra_dc_precision);

            put_be32(pb, codec->me_method);

            put_be32(pb, codec->mb_decision);

            put_be32(pb, codec->nsse_weight);

            put_be32(pb, codec->frame_skip_cmp);

            put_be64(pb, av_dbl2int(codec->rc_buffer_aggressivity));

            put_be32(pb, codec->codec_tag);

            put_byte(pb, codec->thread_count);

            break;

        case CODEC_TYPE_AUDIO:

            put_be32(pb, codec->sample_rate);

            put_le16(pb, codec->channels);

            put_le16(pb, codec->frame_size);

            break;

        default:

            return -1;

        }

        if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {

            put_be32(pb, codec->extradata_size);

            put_buffer(pb, codec->extradata, codec->extradata_size);

        }

    }

    /* flush until end of block reached */

    while ((url_ftell(pb) % ffm->packet_size) != 0)

        put_byte(pb, 0);

    put_flush_packet(pb);

    /* init packet mux */

    ffm->packet_ptr = ffm->packet;

    ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE;

    assert(ffm->packet_end >= ffm->packet);

    ffm->frame_offset = 0;

    ffm->dts = 0;

    ffm->first_packet = 1;

    return 0;

}


static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)

{

    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);

    PCIRegion *pci_region = dev->real_device.regions;

    int ret, pos;

    Error *local_err = NULL;

    /* Clear initial capabilities pointer and status copied from hw */

    pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0);

    pci_set_word(pci_dev->config + PCI_STATUS,

                 pci_get_word(pci_dev->config + PCI_STATUS) &

                 ~PCI_STATUS_CAP_LIST);

    /* Expose MSI capability

     * MSI capability is the 1st capability in capability config */

    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0);

    if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) {

        verify_irqchip_in_kernel(&local_err);

        if (local_err) {

            error_propagate(errp, local_err);

            return -ENOTSUP;

        }

        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;

        /* Only 32-bit/no-mask currently supported */

        ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSI, pos, 10,

                                  &local_err);

        if (ret < 0) {

            error_propagate(errp, local_err);

            return ret;

        }

        pci_dev->msi_cap = pos;

        pci_set_word(pci_dev->config + pos + PCI_MSI_FLAGS,

                     pci_get_word(pci_dev->config + pos + PCI_MSI_FLAGS) &

                     PCI_MSI_FLAGS_QMASK);

        pci_set_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO, 0);

        pci_set_word(pci_dev->config + pos + PCI_MSI_DATA_32, 0);

        /* Set writable fields */

        pci_set_word(pci_dev->wmask + pos + PCI_MSI_FLAGS,

                     PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);

        pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc);

        pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff);

    }

    /* Expose MSI-X capability */

    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0);

    if (pos != 0 && kvm_device_msix_supported(kvm_state)) {

        int bar_nr;

        uint32_t msix_table_entry;

        verify_irqchip_in_kernel(&local_err);

        if (local_err) {

            error_propagate(errp, local_err);

            return -ENOTSUP;

        }

        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;

        ret = pci_add_capability2(pci_dev, PCI_CAP_ID_MSIX, pos, 12,

                                  &local_err);

        if (ret < 0) {

            error_propagate(errp, local_err);

            return ret;

        }

        pci_dev->msix_cap = pos;

        pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS,

                     pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) &

                     PCI_MSIX_FLAGS_QSIZE);

        /* Only enable and function mask bits are writable */

        pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS,

                     PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);

        msix_table_entry = pci_get_long(pci_dev->config + pos + PCI_MSIX_TABLE);

        bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK;

        msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK;

        dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry;

        dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS);

        dev->msix_max &= PCI_MSIX_FLAGS_QSIZE;

        dev->msix_max += 1;

    }

    /* Minimal PM support, nothing writable, device appears to NAK changes */

    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PM, 0);

    if (pos) {

        uint16_t pmc;

        ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF,

                                  &local_err);

        if (ret < 0) {

            error_propagate(errp, local_err);

            return ret;

        }

        assigned_dev_setup_cap_read(dev, pos, PCI_PM_SIZEOF);

        pmc = pci_get_word(pci_dev->config + pos + PCI_CAP_FLAGS);

        pmc &= (PCI_PM_CAP_VER_MASK | PCI_PM_CAP_DSI);

        pci_set_word(pci_dev->config + pos + PCI_CAP_FLAGS, pmc);

        /* assign_device will bring the device up to D0, so we don't need

         * to worry about doing that ourselves here. */

        pci_set_word(pci_dev->config + pos + PCI_PM_CTRL,

                     PCI_PM_CTRL_NO_SOFT_RESET);

        pci_set_byte(pci_dev->config + pos + PCI_PM_PPB_EXTENSIONS, 0);

        pci_set_byte(pci_dev->config + pos + PCI_PM_DATA_REGISTER, 0);

    }

    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_EXP, 0);

    if (pos) {

        uint8_t version, size = 0;

        uint16_t type, devctl, lnksta;

        uint32_t devcap, lnkcap;

        version = pci_get_byte(pci_dev->config + pos + PCI_EXP_FLAGS);

        version &= PCI_EXP_FLAGS_VERS;

        if (version == 1) {

            size = 0x14;

        } else if (version == 2) {

            /*

             * Check for non-std size, accept reduced size to 0x34,

             * which is what bcm5761 implemented, violating the

             * PCIe v3.0 spec that regs should exist and be read as 0,

             * not optionally provided and shorten the struct size.

             */

            size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos);

            if (size < 0x34) {

                error_setg(errp, "Invalid size PCIe cap-id 0x%x",

                           PCI_CAP_ID_EXP);

                return -EINVAL;

            } else if (size != 0x3c) {

                error_report("WARNING, %s: PCIe cap-id 0x%x has "

                             "non-standard size 0x%x; std size should be 0x3c",

                             __func__, PCI_CAP_ID_EXP, size);

            }

        } else if (version == 0) {

            uint16_t vid, did;

            vid = pci_get_word(pci_dev->config + PCI_VENDOR_ID);

            did = pci_get_word(pci_dev->config + PCI_DEVICE_ID);

            if (vid == PCI_VENDOR_ID_INTEL && did == 0x10ed) {

                /*

                 * quirk for Intel 82599 VF with invalid PCIe capability

                 * version, should really be version 2 (same as PF)

                 */

                size = 0x3c;

            }

        }

        if (size == 0) {

            error_setg(errp, "Unsupported PCI express capability version %d",

                       version);

            return -EINVAL;

        }

        ret = pci_add_capability2(pci_dev, PCI_CAP_ID_EXP, pos, size,

                                  &local_err);

        if (ret < 0) {

            error_propagate(errp, local_err);

            return ret;

        }

        assigned_dev_setup_cap_read(dev, pos, size);

        type = pci_get_word(pci_dev->config + pos + PCI_EXP_FLAGS);

        type = (type & PCI_EXP_FLAGS_TYPE) >> 4;

        if (type != PCI_EXP_TYPE_ENDPOINT &&

            type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) {

            error_setg(errp, "Device assignment only supports endpoint "

                       "assignment, device type %d", type);

            return -EINVAL;

        }

        /* capabilities, pass existing read-only copy

         * PCI_EXP_FLAGS_IRQ: updated by hardware, should be direct read */

        /* device capabilities: hide FLR */

        devcap = pci_get_long(pci_dev->config + pos + PCI_EXP_DEVCAP);

        devcap &= ~PCI_EXP_DEVCAP_FLR;

        pci_set_long(pci_dev->config + pos + PCI_EXP_DEVCAP, devcap);

        /* device control: clear all error reporting enable bits, leaving

         *                 only a few host values.  Note, these are

         *                 all writable, but not passed to hw.

         */

        devctl = pci_get_word(pci_dev->config + pos + PCI_EXP_DEVCTL);

        devctl = (devctl & (PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_PAYLOAD)) |

                  PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN;

        pci_set_word(pci_dev->config + pos + PCI_EXP_DEVCTL, devctl);

        devctl = PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_AUX_PME;

        pci_set_word(pci_dev->wmask + pos + PCI_EXP_DEVCTL, ~devctl);

        /* Clear device status */

        pci_set_word(pci_dev->config + pos + PCI_EXP_DEVSTA, 0);

        /* Link capabilities, expose links and latencues, clear reporting */

        lnkcap = pci_get_long(pci_dev->config + pos + PCI_EXP_LNKCAP);

        lnkcap &= (PCI_EXP_LNKCAP_SLS | PCI_EXP_LNKCAP_MLW |

                   PCI_EXP_LNKCAP_ASPMS | PCI_EXP_LNKCAP_L0SEL |

                   PCI_EXP_LNKCAP_L1EL);

        pci_set_long(pci_dev->config + pos + PCI_EXP_LNKCAP, lnkcap);

        /* Link control, pass existing read-only copy.  Should be writable? */

        /* Link status, only expose current speed and width */

        lnksta = pci_get_word(pci_dev->config + pos + PCI_EXP_LNKSTA);

        lnksta &= (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);

        pci_set_word(pci_dev->config + pos + PCI_EXP_LNKSTA, lnksta);

        if (version >= 2) {

            /* Slot capabilities, control, status - not needed for endpoints */

            pci_set_long(pci_dev->config + pos + PCI_EXP_SLTCAP, 0);

            pci_set_word(pci_dev->config + pos + PCI_EXP_SLTCTL, 0);

            pci_set_word(pci_dev->config + pos + PCI_EXP_SLTSTA, 0);

            /* Root control, capabilities, status - not needed for endpoints */

            pci_set_word(pci_dev->config + pos + PCI_EXP_RTCTL, 0);

            pci_set_word(pci_dev->config + pos + PCI_EXP_RTCAP, 0);

            pci_set_long(pci_dev->config + pos + PCI_EXP_RTSTA, 0);

            /* Device capabilities/control 2, pass existing read-only copy */

            /* Link control 2, pass existing read-only copy */

        }

    }

    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PCIX, 0);

    if (pos) {

        uint16_t cmd;

        uint32_t status;

        /* Only expose the minimum, 8 byte capability */

        ret = pci_add_capability2(pci_dev, PCI_CAP_ID_PCIX, pos, 8,

                                  &local_err);

        if (ret < 0) {

            error_propagate(errp, local_err);

            return ret;

        }

        assigned_dev_setup_cap_read(dev, pos, 8);

        /* Command register, clear upper bits, including extended modes */

        cmd = pci_get_word(pci_dev->config + pos + PCI_X_CMD);

        cmd &= (PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO | PCI_X_CMD_MAX_READ |

                PCI_X_CMD_MAX_SPLIT);

        pci_set_word(pci_dev->config + pos + PCI_X_CMD, cmd);

        /* Status register, update with emulated PCI bus location, clear

         * error bits, leave the rest. */

        status = pci_get_long(pci_dev->config + pos + PCI_X_STATUS);

        status &= ~(PCI_X_STATUS_BUS | PCI_X_STATUS_DEVFN);

        status |= (pci_bus_num(pci_dev->bus) << 8) | pci_dev->devfn;

        status &= ~(PCI_X_STATUS_SPL_DISC | PCI_X_STATUS_UNX_SPL |

                    PCI_X_STATUS_SPL_ERR);

        pci_set_long(pci_dev->config + pos + PCI_X_STATUS, status);

    }

    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0);

    if (pos) {

        /* Direct R/W passthrough */

        ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VPD, pos, 8,

                                  &local_err);

        if (ret < 0) {

            error_propagate(errp, local_err);

            return ret;

        }

        assigned_dev_setup_cap_read(dev, pos, 8);

        /* direct write for cap content */

        assigned_dev_direct_config_write(dev, pos + 2, 6);

    }

    /* Devices can have multiple vendor capabilities, get them all */

    for (pos = 0; (pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VNDR, pos));

        pos += PCI_CAP_LIST_NEXT) {

        uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS);

        /* Direct R/W passthrough */

        ret = pci_add_capability2(pci_dev, PCI_CAP_ID_VNDR, pos, len,

                                  &local_err);

        if (ret < 0) {

            error_propagate(errp, local_err);

            return ret;

        }

        assigned_dev_setup_cap_read(dev, pos, len);

        /* direct write for cap content */

        assigned_dev_direct_config_write(dev, pos + 2, len - 2);

    }

    /* If real and virtual capability list status bits differ, virtualize the

     * access. */

    if ((pci_get_word(pci_dev->config + PCI_STATUS) & PCI_STATUS_CAP_LIST) !=

        (assigned_dev_pci_read_byte(pci_dev, PCI_STATUS) &

         PCI_STATUS_CAP_LIST)) {

        dev->emulate_config_read[PCI_STATUS] |= PCI_STATUS_CAP_LIST;

    }

    return 0;

}


int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags)

{

    int i, r = AVERROR(ENOSYS);

    if(!graph)

        return r;

    if((flags & AVFILTER_CMD_FLAG_ONE) && !(flags & AVFILTER_CMD_FLAG_FAST)) {

        r=avfilter_graph_send_command(graph, target, cmd, arg, res, res_len, flags | AVFILTER_CMD_FLAG_FAST);

        if(r != AVERROR(ENOSYS))

            return r;

    }

    if(res_len && res)

        res[0]= 0;

    for (i = 0; i < graph->filter_count; i++) {

        AVFilterContext *filter = graph->filters[i];

        if(!strcmp(target, "all") || !strcmp(target, filter->name) || !strcmp(target, filter->filter->name)){

            r = avfilter_process_command(filter, cmd, arg, res, res_len, flags);

            if(r != AVERROR(ENOSYS)) {

                if((flags & AVFILTER_CMD_FLAG_ONE) || r<0)

                    return r;

            }

        }

    }

    return r;

}


static void dct_unquantize_mpeg2_c(MpegEncContext *s,

                                   DCTELEM *block, int n, int qscale)

{

    int i, level, nCoeffs;

    const UINT16 *quant_matrix;

    if(s->alternate_scan) nCoeffs= 64;

    else nCoeffs= s->block_last_index[n]+1;

    if (s->mb_intra) {

        if (n < 4)

            block[0] = block[0] * s->y_dc_scale;

        else

            block[0] = block[0] * s->c_dc_scale;

        quant_matrix = s->intra_matrix;

        for(i=1;i<nCoeffs;i++) {

            int j= zigzag_direct[i];

            level = block[j];

            if (level) {

                if (level < 0) {

                    level = -level;

                    level = (int)(level * qscale * quant_matrix[j]) >> 3;

                    level = -level;

                } else {

                    level = (int)(level * qscale * quant_matrix[j]) >> 3;

                }

#ifdef PARANOID

                if (level < -2048 || level > 2047)

                    fprintf(stderr, "unquant error %d %d\n", i, level);

#endif

                block[j] = level;

            }

        }

    } else {

        int sum=-1;

        i = 0;

        quant_matrix = s->non_intra_matrix;

        for(;i<nCoeffs;i++) {

            int j= zigzag_direct[i];

            level = block[j];

            if (level) {

                if (level < 0) {

                    level = -level;

                    level = (((level << 1) + 1) * qscale *

                             ((int) (quant_matrix[j]))) >> 4;

                    level = -level;

                } else {

                    level = (((level << 1) + 1) * qscale *

                             ((int) (quant_matrix[j]))) >> 4;

                }

#ifdef PARANOID

                if (level < -2048 || level > 2047)

                    fprintf(stderr, "unquant error %d %d\n", i, level);

#endif

                block[j] = level;

                sum+=level;

            }

        }

        block[63]^=sum&1;

    }

}


static void destroy_l2_mapping(PhysPageEntry *lp, unsigned level)

{

    unsigned i;

    PhysPageEntry *p;

    if (lp->ptr == PHYS_MAP_NODE_NIL) {

        return;

    }

    p = phys_map_nodes[lp->ptr];

    for (i = 0; i < L2_SIZE; ++i) {

        if (!p[i].is_leaf) {

            destroy_l2_mapping(&p[i], level - 1);

        } else {

            destroy_page_desc(p[i].ptr);

        }

    }

    lp->is_leaf = 0;

    lp->ptr = PHYS_MAP_NODE_NIL;

}


static int apply_window_and_mdct(vorbis_enc_context *venc,

                                 float **audio, int samples)

{

    int channel;

    const float * win = venc->win[0];

    int window_len = 1 << (venc->log2_blocksize[0] - 1);

    float n = (float)(1 << venc->log2_blocksize[0]) / 4.0;

    AVFloatDSPContext *fdsp = venc->fdsp;

    if (!venc->have_saved && !samples)

        return 0;

    if (venc->have_saved) {

        for (channel = 0; channel < venc->channels; channel++)

            memcpy(venc->samples + channel * window_len * 2,

                   venc->saved + channel * window_len, sizeof(float) * window_len);

    } else {

        for (channel = 0; channel < venc->channels; channel++)

            memset(venc->samples + channel * window_len * 2, 0,

                   sizeof(float) * window_len);

    }

    if (samples) {

        for (channel = 0; channel < venc->channels; channel++) {

            float *offset = venc->samples + channel * window_len * 2 + window_len;

            fdsp->vector_fmul_reverse(offset, audio[channel], win, samples);

            fdsp->vector_fmul_scalar(offset, offset, 1/n, samples);

        }

    } else {

        for (channel = 0; channel < venc->channels; channel++)

            memset(venc->samples + channel * window_len * 2 + window_len,

                   0, sizeof(float) * window_len);

    }

    for (channel = 0; channel < venc->channels; channel++)

        venc->mdct[0].mdct_calc(&venc->mdct[0], venc->coeffs + channel * window_len,

                     venc->samples + channel * window_len * 2);

    if (samples) {

        for (channel = 0; channel < venc->channels; channel++) {

            float *offset = venc->saved + channel * window_len;

            fdsp->vector_fmul(offset, audio[channel], win, samples);

            fdsp->vector_fmul_scalar(offset, offset, 1/n, samples);

        }

        venc->have_saved = 1;

    } else {

        venc->have_saved = 0;

    }

    return 1;

}


static int transcode(void)

{

    int ret, i;

    AVFormatContext *is, *os;

    OutputStream *ost;

    InputStream *ist;

    uint8_t *no_packet;

    int no_packet_count = 0;

    int64_t timer_start;

    int key;

    if (!(no_packet = av_mallocz(nb_input_files)))

        exit_program(1);

    ret = transcode_init();

    if (ret < 0)

        goto fail;

    if (!using_stdin) {

        av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");

    }

    timer_start = av_gettime();

    for (; received_sigterm == 0;) {

        int file_index, ist_index;

        AVPacket pkt;

        int64_t cur_time= av_gettime();

        /* if 'q' pressed, exits */

        if (!using_stdin) {

            static int64_t last_time;

            if (received_nb_signals)

                break;

            /* read_key() returns 0 on EOF */

            if(cur_time - last_time >= 100000 && !run_as_daemon){

                key =  read_key();

                last_time = cur_time;

            }else

                key = -1;

            if (key == 'q')

                break;

            if (key == '+') av_log_set_level(av_log_get_level()+10);

            if (key == '-') av_log_set_level(av_log_get_level()-10);

            if (key == 's') qp_hist     ^= 1;

            if (key == 'h'){

                if (do_hex_dump){

                    do_hex_dump = do_pkt_dump = 0;

                } else if(do_pkt_dump){

                    do_hex_dump = 1;

                } else

                    do_pkt_dump = 1;

                av_log_set_level(AV_LOG_DEBUG);

            }

            if (key == 'c' || key == 'C'){

                char buf[4096], target[64], command[256], arg[256] = {0};

                double time;

                int k, n = 0;

                fprintf(stderr, "\nEnter command: <target> <time> <command>[ <argument>]\n");

                i = 0;

                while ((k = read_key()) != '\n' && k != '\r' && i < sizeof(buf)-1)

                    if (k > 0)

                        buf[i++] = k;

                buf[i] = 0;

                if (k > 0 &&

                    (n = sscanf(buf, "%63[^ ] %lf %255[^ ] %255[^\n]", target, &time, command, arg)) >= 3) {

                    av_log(NULL, AV_LOG_DEBUG, "Processing command target:%s time:%f command:%s arg:%s",

                           target, time, command, arg);

                    for (i = 0; i < nb_filtergraphs; i++) {

                        FilterGraph *fg = filtergraphs[i];

                        if (fg->graph) {

                            if (time < 0) {

                                ret = avfilter_graph_send_command(fg->graph, target, command, arg, buf, sizeof(buf),

                                                                  key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0);

                                fprintf(stderr, "Command reply for stream %d: ret:%d res:%s\n", i, ret, buf);

                            } else {

                                ret = avfilter_graph_queue_command(fg->graph, target, command, arg, 0, time);

                            }

                        }

                    }

                } else {

                    av_log(NULL, AV_LOG_ERROR,

                           "Parse error, at least 3 arguments were expected, "

                           "only %d given in string '%s'\n", n, buf);

                }

            }

            if (key == 'd' || key == 'D'){

                int debug=0;

                if(key == 'D') {

                    debug = input_streams[0]->st->codec->debug<<1;

                    if(!debug) debug = 1;

                    while(debug & (FF_DEBUG_DCT_COEFF|FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) //unsupported, would just crash

                        debug += debug;

                }else

                    if(scanf("%d", &debug)!=1)

                        fprintf(stderr,"error parsing debug value\n");

                for(i=0;i<nb_input_streams;i++) {

                    input_streams[i]->st->codec->debug = debug;

                }

                for(i=0;i<nb_output_streams;i++) {

                    ost = output_streams[i];

                    ost->st->codec->debug = debug;

                }

                if(debug) av_log_set_level(AV_LOG_DEBUG);

                fprintf(stderr,"debug=%d\n", debug);

            }

            if (key == '?'){

                fprintf(stderr, "key    function\n"

                                "?      show this help\n"

                                "+      increase verbosity\n"

                                "-      decrease verbosity\n"

                                "c      Send command to filtergraph\n"

                                "D      cycle through available debug modes\n"

                                "h      dump packets/hex press to cycle through the 3 states\n"

                                "q      quit\n"

                                "s      Show QP histogram\n"

                );

            }

        }

        /* check if there's any stream where output is still needed */

        if (!need_output()) {

            av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");

            break;

        }

        /* select the stream that we must read now */

        file_index = select_input_file(no_packet);

        /* if none, if is finished */

        if (file_index < 0) {

            if (no_packet_count) {

                no_packet_count = 0;

                memset(no_packet, 0, nb_input_files);

                usleep(10000);

                continue;

            }

            break;

        }

        /* read a frame from it and output it in the fifo */

        is  = input_files[file_index]->ctx;

        ret = av_read_frame(is, &pkt);

        if (ret == AVERROR(EAGAIN)) {

            no_packet[file_index] = 1;

            no_packet_count++;

            continue;

        }

        if (ret < 0) {

            input_files[file_index]->eof_reached = 1;

            for (i = 0; i < input_files[file_index]->nb_streams; i++) {

                ist = input_streams[input_files[file_index]->ist_index + i];

                if (ist->decoding_needed)

                    output_packet(ist, NULL);

            }

            if (opt_shortest)

                break;

            else

                continue;

        }

        no_packet_count = 0;

        memset(no_packet, 0, nb_input_files);

        if (do_pkt_dump) {

            av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,

                             is->streams[pkt.stream_index]);

        }

        /* the following test is needed in case new streams appear

           dynamically in stream : we ignore them */

        if (pkt.stream_index >= input_files[file_index]->nb_streams)

            goto discard_packet;

        ist_index = input_files[file_index]->ist_index + pkt.stream_index;

        ist = input_streams[ist_index];

        if (ist->discard)

            goto discard_packet;

        if (pkt.dts != AV_NOPTS_VALUE)

            pkt.dts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);

        if (pkt.pts != AV_NOPTS_VALUE)

            pkt.pts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);

        if (pkt.pts != AV_NOPTS_VALUE)

            pkt.pts *= ist->ts_scale;

        if (pkt.dts != AV_NOPTS_VALUE)

            pkt.dts *= ist->ts_scale;

        if (debug_ts) {

            av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d type:%s "

                    "next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s  pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%"PRId64"\n",

                    ist_index, av_get_media_type_string(ist->st->codec->codec_type),

                    av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &ist->st->time_base),

                    av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &ist->st->time_base),

                    av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),

                    av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),

                    input_files[ist->file_index]->ts_offset);

        }

        if (pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE && !copy_ts) {

            int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);

            int64_t delta   = pkt_dts - ist->next_dts;

            if (is->iformat->flags & AVFMT_TS_DISCONT) {

            if(delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||

                (delta > 1LL*dts_delta_threshold*AV_TIME_BASE &&

                 ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||

                pkt_dts+1<ist->pts){

                input_files[ist->file_index]->ts_offset -= delta;

                av_log(NULL, AV_LOG_DEBUG,

                       "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",

                       delta, input_files[ist->file_index]->ts_offset);

                pkt.dts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);

                if (pkt.pts != AV_NOPTS_VALUE)

                    pkt.pts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);

            }

            } else {

                if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||

                    (delta > 1LL*dts_error_threshold*AV_TIME_BASE && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||

                     pkt_dts+1<ist->pts){

                    av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt.dts, ist->next_dts, pkt.stream_index);

                    pkt.dts = AV_NOPTS_VALUE;

                }

                if (pkt.pts != AV_NOPTS_VALUE){

                    int64_t pkt_pts = av_rescale_q(pkt.pts, ist->st->time_base, AV_TIME_BASE_Q);

                    delta   = pkt_pts - ist->next_dts;

                    if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||

                        (delta > 1LL*dts_error_threshold*AV_TIME_BASE && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||

                        pkt_pts+1<ist->pts) {

                        av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt.pts, ist->next_dts, pkt.stream_index);

                        pkt.pts = AV_NOPTS_VALUE;

                    }

                }

            }

        }

        // fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);

        if ((ret = output_packet(ist, &pkt)) < 0 ||

            ((ret = poll_filters()) < 0 && ret != AVERROR_EOF)) {

            char buf[128];

            av_strerror(ret, buf, sizeof(buf));

            av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",

                   ist->file_index, ist->st->index, buf);

            if (exit_on_error)

                exit_program(1);

            av_free_packet(&pkt);

            continue;

        }

    discard_packet:

        av_free_packet(&pkt);

        /* dump report by using the output first video and audio streams */

        print_report(0, timer_start, cur_time);

    }

    /* at the end of stream, we must flush the decoder buffers */

    for (i = 0; i < nb_input_streams; i++) {

        ist = input_streams[i];

        if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {

            output_packet(ist, NULL);

        }

    }

    poll_filters();

    flush_encoders();

    term_exit();

    /* write the trailer if needed and close file */

    for (i = 0; i < nb_output_files; i++) {

        os = output_files[i]->ctx;

        av_write_trailer(os);

    }

    /* dump report by using the first video and audio streams */

    print_report(1, timer_start, av_gettime());

    /* close each encoder */

    for (i = 0; i < nb_output_streams; i++) {

        ost = output_streams[i];

        if (ost->encoding_needed) {

            av_freep(&ost->st->codec->stats_in);

            avcodec_close(ost->st->codec);

        }

    }

    /* close each decoder */

    for (i = 0; i < nb_input_streams; i++) {

        ist = input_streams[i];

        if (ist->decoding_needed) {

            avcodec_close(ist->st->codec);

        }

    }

    /* finished ! */

    ret = 0;

 fail:

    av_freep(&no_packet);

    if (output_streams) {

        for (i = 0; i < nb_output_streams; i++) {

            ost = output_streams[i];

            if (ost) {

                if (ost->stream_copy)

                    av_freep(&ost->st->codec->extradata);

                if (ost->logfile) {

                    fclose(ost->logfile);

                    ost->logfile = NULL;

                }

                av_freep(&ost->st->codec->subtitle_header);

                av_free(ost->forced_kf_pts);

                av_dict_free(&ost->opts);

            }

        }

    }

    return ret;

}


static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt)

{

    RTSPState *rt = s->priv_data;

    RTSPStream *rtsp_st;

    fd_set rfds;

    int n, tcp_fd;

    struct timeval tv;

    AVFormatContext *rtpctx;

    int ret;

    tcp_fd = url_get_file_handle(rt->rtsp_hd);

    while (1) {

        FD_ZERO(&rfds);

        FD_SET(tcp_fd, &rfds);

        tv.tv_sec = 0;

        tv.tv_usec = 0;

        n = select(tcp_fd + 1, &rfds, NULL, NULL, &tv);

        if (n <= 0)

            break;

        if (FD_ISSET(tcp_fd, &rfds)) {

            RTSPMessageHeader reply;

            /* Don't let ff_rtsp_read_reply handle interleaved packets,

             * since it would block and wait for an RTSP reply on the socket

             * (which may not be coming any time soon) if it handles

             * interleaved packets internally. */

            ret = ff_rtsp_read_reply(s, &reply, NULL, 1, NULL);

            if (ret < 0)

                return AVERROR(EPIPE);

            if (ret == 1)

                ff_rtsp_skip_packet(s);

            /* XXX: parse message */

            if (rt->state != RTSP_STATE_STREAMING)

                return AVERROR(EPIPE);

        }

    }

    if (pkt->stream_index < 0 || pkt->stream_index >= rt->nb_rtsp_streams)

        return AVERROR_INVALIDDATA;

    rtsp_st = rt->rtsp_streams[pkt->stream_index];

    rtpctx = rtsp_st->transport_priv;

    ret = ff_write_chained(rtpctx, 0, pkt, s);

    /* ff_write_chained does all the RTP packetization. If using TCP as

     * transport, rtpctx->pb is only a dyn_packet_buf that queues up the

     * packets, so we need to send them out on the TCP connection separately.

     */

    if (!ret && rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP)

        ret = tcp_write_packet(s, rtsp_st);

    return ret;

}


static inline TCGv load_reg(DisasContext *s, int reg)

{

    TCGv tmp = new_tmp();

    load_reg_var(s, tmp, reg);

    return tmp;

}


static void ppc_spapr_init(QEMUMachineInitArgs *args)

{

    ram_addr_t ram_size = args->ram_size;

    const char *cpu_model = args->cpu_model;

    const char *kernel_filename = args->kernel_filename;

    const char *kernel_cmdline = args->kernel_cmdline;

    const char *initrd_filename = args->initrd_filename;

    const char *boot_device = args->boot_device;

    PowerPCCPU *cpu;

    CPUPPCState *env;

    PCIHostState *phb;

    int i;

    MemoryRegion *sysmem = get_system_memory();

    MemoryRegion *ram = g_new(MemoryRegion, 1);

    hwaddr rma_alloc_size;

    uint32_t initrd_base = 0;

    long kernel_size = 0, initrd_size = 0;

    long load_limit, rtas_limit, fw_size;

    char *filename;

    msi_supported = true;

    spapr = g_malloc0(sizeof(*spapr));

    QLIST_INIT(&spapr->phbs);

    cpu_ppc_hypercall = emulate_spapr_hypercall;

    /* Allocate RMA if necessary */

    rma_alloc_size = kvmppc_alloc_rma("ppc_spapr.rma", sysmem);

    if (rma_alloc_size == -1) {

        hw_error("qemu: Unable to create RMA\n");

        exit(1);

    }

    if (rma_alloc_size && (rma_alloc_size < ram_size)) {

        spapr->rma_size = rma_alloc_size;

    } else {

        spapr->rma_size = ram_size;

        /* With KVM, we don't actually know whether KVM supports an

         * unbounded RMA (PR KVM) or is limited by the hash table size

         * (HV KVM using VRMA), so we always assume the latter

         *

         * In that case, we also limit the initial allocations for RTAS

         * etc... to 256M since we have no way to know what the VRMA size

         * is going to be as it depends on the size of the hash table

         * isn't determined yet.

         */

        if (kvm_enabled()) {

            spapr->vrma_adjust = 1;

            spapr->rma_size = MIN(spapr->rma_size, 0x10000000);

        }

    }

    /* We place the device tree and RTAS just below either the top of the RMA,

     * or just below 2GB, whichever is lowere, so that it can be

     * processed with 32-bit real mode code if necessary */

    rtas_limit = MIN(spapr->rma_size, 0x80000000);

    spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;

    spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;

    load_limit = spapr->fdt_addr - FW_OVERHEAD;

    /* We aim for a hash table of size 1/128 the size of RAM.  The

     * normal rule of thumb is 1/64 the size of RAM, but that's much

     * more than needed for the Linux guests we support. */

    spapr->htab_shift = 18; /* Minimum architected size */

    while (spapr->htab_shift <= 46) {

        if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) {

            break;

        }

        spapr->htab_shift++;

    }

    /* init CPUs */

    if (cpu_model == NULL) {

        cpu_model = kvm_enabled() ? "host" : "POWER7";

    }

    for (i = 0; i < smp_cpus; i++) {

        cpu = cpu_ppc_init(cpu_model);

        if (cpu == NULL) {

            fprintf(stderr, "Unable to find PowerPC CPU definition\n");

            exit(1);

        }

        env = &cpu->env;

        /* Set time-base frequency to 512 MHz */

        cpu_ppc_tb_init(env, TIMEBASE_FREQ);

        /* PAPR always has exception vectors in RAM not ROM */

        env->hreset_excp_prefix = 0;

        /* Tell KVM that we're in PAPR mode */

        if (kvm_enabled()) {

            kvmppc_set_papr(cpu);

        }

        qemu_register_reset(spapr_cpu_reset, cpu);

    }

    /* allocate RAM */

    spapr->ram_limit = ram_size;

    if (spapr->ram_limit > rma_alloc_size) {

        ram_addr_t nonrma_base = rma_alloc_size;

        ram_addr_t nonrma_size = spapr->ram_limit - rma_alloc_size;

        memory_region_init_ram(ram, "ppc_spapr.ram", nonrma_size);

        vmstate_register_ram_global(ram);

        memory_region_add_subregion(sysmem, nonrma_base, ram);

    }

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");

    spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,

                                           rtas_limit - spapr->rtas_addr);

    if (spapr->rtas_size < 0) {

        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);

        exit(1);

    }

    if (spapr->rtas_size > RTAS_MAX_SIZE) {

        hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n",

                 spapr->rtas_size, RTAS_MAX_SIZE);

        exit(1);

    }

    g_free(filename);

    /* Set up Interrupt Controller */

    spapr->icp = xics_system_init(XICS_IRQS);

    spapr->next_irq = XICS_IRQ_BASE;

    /* Set up EPOW events infrastructure */

    spapr_events_init(spapr);

    /* Set up IOMMU */

    spapr_iommu_init();

    /* Set up VIO bus */

    spapr->vio_bus = spapr_vio_bus_init();

    for (i = 0; i < MAX_SERIAL_PORTS; i++) {

        if (serial_hds[i]) {

            spapr_vty_create(spapr->vio_bus, serial_hds[i]);

        }

    }

    /* We always have at least the nvram device on VIO */

    spapr_create_nvram(spapr);

    /* Set up PCI */

    spapr_pci_rtas_init();

    spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID,

                     SPAPR_PCI_MEM_WIN_ADDR,

                     SPAPR_PCI_MEM_WIN_SIZE,

                     SPAPR_PCI_IO_WIN_ADDR,

                     SPAPR_PCI_MSI_WIN_ADDR);

    phb = PCI_HOST_BRIDGE(QLIST_FIRST(&spapr->phbs));

    for (i = 0; i < nb_nics; i++) {

        NICInfo *nd = &nd_table[i];

        if (!nd->model) {

            nd->model = g_strdup("ibmveth");

        }

        if (strcmp(nd->model, "ibmveth") == 0) {

            spapr_vlan_create(spapr->vio_bus, nd);

        } else {

            pci_nic_init_nofail(&nd_table[i], nd->model, NULL);

        }

    }

    for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {

        spapr_vscsi_create(spapr->vio_bus);

    }

    /* Graphics */

    if (spapr_vga_init(phb->bus)) {

        spapr->has_graphics = true;

    }

    if (usb_enabled(spapr->has_graphics)) {

        pci_create_simple(phb->bus, -1, "pci-ohci");

        if (spapr->has_graphics) {

            usbdevice_create("keyboard");

            usbdevice_create("mouse");

        }

    }

    if (spapr->rma_size < (MIN_RMA_SLOF << 20)) {

        fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "

                "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);

        exit(1);

    }

    if (kernel_filename) {

        uint64_t lowaddr = 0;

        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,

                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);

        if (kernel_size < 0) {

            kernel_size = load_image_targphys(kernel_filename,

                                              KERNEL_LOAD_ADDR,

                                              load_limit - KERNEL_LOAD_ADDR);

        }

        if (kernel_size < 0) {

            fprintf(stderr, "qemu: could not load kernel '%s'\n",

                    kernel_filename);

            exit(1);

        }

        /* load initrd */

        if (initrd_filename) {

            /* Try to locate the initrd in the gap between the kernel

             * and the firmware. Add a bit of space just in case

             */

            initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff;

            initrd_size = load_image_targphys(initrd_filename, initrd_base,

                                              load_limit - initrd_base);

            if (initrd_size < 0) {

                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",

                        initrd_filename);

                exit(1);

            }

        } else {

            initrd_base = 0;

            initrd_size = 0;

        }

    }

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);

    fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);

    if (fw_size < 0) {

        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);

        exit(1);

    }

    g_free(filename);

    spapr->entry_point = 0x100;

    /* Prepare the device tree */

    spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,

                                            initrd_base, initrd_size,

                                            kernel_size,

                                            boot_device, kernel_cmdline,

                                            spapr->epow_irq);

    assert(spapr->fdt_skel != NULL);

}


static void hmp_info_cpustats(Monitor *mon, const QDict *qdict)

{

    cpu_dump_statistics(mon_get_cpu(), (FILE *)mon, &monitor_fprintf, 0);

}


static int read_decode_block(ALSDecContext *ctx, ALSBlockData *bd)

{

    int ret;

    ret = read_block(ctx, bd);

    if (ret)

        return ret;

    ret = decode_block(ctx, bd);

    return ret;

}


DeviceState *aux_create_slave(AUXBus *bus, const char *type, uint32_t addr)

{

    DeviceState *dev;

    dev = DEVICE(object_new(type));

    assert(dev);

    qdev_set_parent_bus(dev, &bus->qbus);

    qdev_init_nofail(dev);

    aux_bus_map_device(AUX_BUS(qdev_get_parent_bus(dev)), AUX_SLAVE(dev), addr);

    return dev;

}


static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,

                            VMStateField *field)

{

    uint64_t *v = pv;

    uint64_t v2;

    qemu_get_be64s(f, &v2);

    if (*v == v2) {

        return 0;

    error_report("%" PRIx64 " != %" PRIx64, *v, v2);

    return -EINVAL;


static void vhost_net_stop_one(struct vhost_net *net,

                               VirtIODevice *dev)

{

    struct vhost_vring_file file = { .fd = -1 };

    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {

        for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {

            const VhostOps *vhost_ops = net->dev.vhost_ops;

            int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);

            assert(r >= 0);

        }

    }

    if (net->nc->info->poll) {

        net->nc->info->poll(net->nc, true);

    }

    vhost_dev_stop(&net->dev, dev);

    vhost_dev_disable_notifiers(&net->dev, dev);

}


static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)

{

    uint8_t slot = PCI_SLOT(dev->devfn);

    uint8_t func;

    if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {

        dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;

    }

    /*

     * multifunction bit is interpreted in two ways as follows.

     *   - all functions must set the bit to 1.

     *     Example: Intel X53

     *   - function 0 must set the bit, but the rest function (> 0)

     *     is allowed to leave the bit to 0.

     *     Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10,

     *

     * So OS (at least Linux) checks the bit of only function 0,

     * and doesn't see the bit of function > 0.

     *

     * The below check allows both interpretation.

     */

    if (PCI_FUNC(dev->devfn)) {

        PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)];

        if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) {

            /* function 0 should set multifunction bit */

            error_report("PCI: single function device can't be populated "

                         "in function %x.%x", slot, PCI_FUNC(dev->devfn));

            return -1;

        }

        return 0;

    }

    if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {

        return 0;

    }

    /* function 0 indicates single function, so function > 0 must be NULL */

    for (func = 1; func < PCI_FUNC_MAX; ++func) {

        if (bus->devices[PCI_DEVFN(slot, func)]) {

            error_report("PCI: %x.0 indicates single function, "

                         "but %x.%x is already populated.",

                         slot, slot, func);

            return -1;

        }

    }

    return 0;

}


static int mpeg_mux_init(AVFormatContext *ctx)

{

    MpegMuxContext *s = ctx->priv_data;

    int bitrate, i, mpa_id, mpv_id, mps_id, ac3_id, dts_id, lpcm_id, j;

    AVStream *st;

    StreamInfo *stream;

    int audio_bitrate;

    int video_bitrate;

    s->packet_number = 0;

    s->is_vcd =    (CONFIG_MPEG1VCD_MUXER  && ctx->oformat == &mpeg1vcd_muxer);

    s->is_svcd =   (CONFIG_MPEG2SVCD_MUXER && ctx->oformat == &mpeg2svcd_muxer);

    s->is_mpeg2 = ((CONFIG_MPEG2VOB_MUXER  && ctx->oformat == &mpeg2vob_muxer) ||

                   (CONFIG_MPEG2DVD_MUXER  && ctx->oformat == &mpeg2dvd_muxer) ||

                   (CONFIG_MPEG2SVCD_MUXER && ctx->oformat == &mpeg2svcd_muxer));

    s->is_dvd =    (CONFIG_MPEG2DVD_MUXER  && ctx->oformat == &mpeg2dvd_muxer);

    if(ctx->packet_size)

        s->packet_size = ctx->packet_size;

    else

        s->packet_size = 2048;

    s->vcd_padding_bytes_written = 0;

    s->vcd_padding_bitrate=0;

    s->audio_bound = 0;

    s->video_bound = 0;

    mpa_id = AUDIO_ID;

    ac3_id = AC3_ID;

    dts_id = DTS_ID;

    mpv_id = VIDEO_ID;

    mps_id = SUB_ID;

    lpcm_id = LPCM_ID;

    for(i=0;i<ctx->nb_streams;i++) {

        st = ctx->streams[i];

        stream = av_mallocz(sizeof(StreamInfo));

        if (!stream)

            goto fail;

        st->priv_data = stream;

        av_set_pts_info(st, 64, 1, 90000);

        switch(st->codec->codec_type) {

        case CODEC_TYPE_AUDIO:

            if        (st->codec->codec_id == CODEC_ID_AC3) {

                stream->id = ac3_id++;

            } else if (st->codec->codec_id == CODEC_ID_DTS) {

                stream->id = dts_id++;

            } else if (st->codec->codec_id == CODEC_ID_PCM_S16BE) {

                stream->id = lpcm_id++;

                for(j = 0; j < 4; j++) {

                    if (lpcm_freq_tab[j] == st->codec->sample_rate)

                        break;

                }

                if (j == 4)

                    goto fail;

                if (st->codec->channels > 8)

                    return -1;

                stream->lpcm_header[0] = 0x0c;

                stream->lpcm_header[1] = (st->codec->channels - 1) | (j << 4);

                stream->lpcm_header[2] = 0x80;

                stream->lpcm_align = st->codec->channels * 2;

            } else {

                stream->id = mpa_id++;

            }

            /* This value HAS to be used for VCD (see VCD standard, p. IV-7).

               Right now it is also used for everything else.*/

            stream->max_buffer_size = 4 * 1024;

            s->audio_bound++;

            break;

        case CODEC_TYPE_VIDEO:

            stream->id = mpv_id++;

            if (st->codec->rc_buffer_size)

                stream->max_buffer_size = 6*1024 + st->codec->rc_buffer_size/8;

            else

                stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default

#if 0

                /* see VCD standard, p. IV-7*/

                stream->max_buffer_size = 46 * 1024;

            else

                /* This value HAS to be used for SVCD (see SVCD standard, p. 26 V.2.3.2).

                   Right now it is also used for everything else.*/

                stream->max_buffer_size = 230 * 1024;

#endif

            s->video_bound++;

            break;

        case CODEC_TYPE_SUBTITLE:

            stream->id = mps_id++;

            stream->max_buffer_size = 16 * 1024;

            break;

        default:

            return -1;

        }

        stream->fifo= av_fifo_alloc(16);

    }

    bitrate = 0;

    audio_bitrate = 0;

    video_bitrate = 0;

    for(i=0;i<ctx->nb_streams;i++) {

        int codec_rate;

        st = ctx->streams[i];

        stream = (StreamInfo*) st->priv_data;

        if(st->codec->rc_max_rate || stream->id==VIDEO_ID)

            codec_rate= st->codec->rc_max_rate;

        else

            codec_rate= st->codec->bit_rate;

        if(!codec_rate)

            codec_rate= (1<<21)*8*50/ctx->nb_streams;

        bitrate += codec_rate;

        if (stream->id==AUDIO_ID)

            audio_bitrate += codec_rate;

        else if (stream->id==VIDEO_ID)

            video_bitrate += codec_rate;

    }

    if(ctx->mux_rate){

        s->mux_rate= (ctx->mux_rate + (8 * 50) - 1) / (8 * 50);

    } else {

        /* we increase slightly the bitrate to take into account the

           headers. XXX: compute it exactly */

        bitrate += bitrate*5/100;

        bitrate += 10000;

        s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50);

    }

    if (s->is_vcd) {

        double overhead_rate;

        /* The VCD standard mandates that the mux_rate field is 3528

           (see standard p. IV-6).

           The value is actually "wrong", i.e. if you calculate

           it using the normal formula and the 75 sectors per second transfer

           rate you get a different value because the real pack size is 2324,

           not 2352. But the standard explicitly specifies that the mux_rate

           field in the header must have this value.*/

//        s->mux_rate=2352 * 75 / 50;    /* = 3528*/

        /* The VCD standard states that the muxed stream must be

           exactly 75 packs / second (the data rate of a single speed cdrom).

           Since the video bitrate (probably 1150000 bits/sec) will be below

           the theoretical maximum we have to add some padding packets

           to make up for the lower data rate.

           (cf. VCD standard p. IV-6 )*/

        /* Add the header overhead to the data rate.

           2279 data bytes per audio pack, 2294 data bytes per video pack*/

        overhead_rate  = ((audio_bitrate / 8.0) / 2279) * (2324 - 2279);

        overhead_rate += ((video_bitrate / 8.0) / 2294) * (2324 - 2294);

        overhead_rate *= 8;

        /* Add padding so that the full bitrate is 2324*75 bytes/sec */

        s->vcd_padding_bitrate = 2324 * 75 * 8 - (bitrate + overhead_rate);

    }

    if (s->is_vcd || s->is_mpeg2)

        /* every packet */

        s->pack_header_freq = 1;

    else

        /* every 2 seconds */

        s->pack_header_freq = 2 * bitrate / s->packet_size / 8;

    /* the above seems to make pack_header_freq zero sometimes */

    if (s->pack_header_freq == 0)

       s->pack_header_freq = 1;

    if (s->is_mpeg2)

        /* every 200 packets. Need to look at the spec.  */

        s->system_header_freq = s->pack_header_freq * 40;

    else if (s->is_vcd)

        /* the standard mandates that there are only two system headers

           in the whole file: one in the first packet of each stream.

           (see standard p. IV-7 and IV-8) */

        s->system_header_freq = 0x7fffffff;

    else

        s->system_header_freq = s->pack_header_freq * 5;

    for(i=0;i<ctx->nb_streams;i++) {

        stream = ctx->streams[i]->priv_data;

        stream->packet_number = 0;

    }

    s->system_header_size = get_system_header_size(ctx);

    s->last_scr = 0;

    return 0;

 fail:

    for(i=0;i<ctx->nb_streams;i++) {

        av_free(ctx->streams[i]->priv_data);

    }

    return AVERROR(ENOMEM);

}