Skip to content
Snippets Groups Projects
utils.c 81.5 KiB
Newer Older
  • Learn to ignore specific revisions
  •         pkt->dts=
    //        pkt->pts= st->cur_dts;
            pkt->pts= st->pts.val;
        }
    
        //calculate dts from pts    
        if(pkt->pts != AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE){
            if(b_frames){
                if(st->last_IP_pts == AV_NOPTS_VALUE){
    
                    st->last_IP_pts= -pkt->duration;
    
                }
                if(st->last_IP_pts < pkt->pts){
                    pkt->dts= st->last_IP_pts;
                    st->last_IP_pts= pkt->pts;
                }else
                    pkt->dts= pkt->pts;
            }else
                pkt->dts= pkt->pts;
        }
        
    
    //    av_log(NULL, AV_LOG_DEBUG, "av_write_frame: pts2:%lld dts2:%lld\n", pkt->pts, pkt->dts);
    
        st->cur_dts= pkt->dts;
        st->pts.val= pkt->dts;
    
    
        /* update pts */
        switch (st->codec.codec_type) {
        case CODEC_TYPE_AUDIO:
    
            frame_size = get_audio_frame_size(&st->codec, pkt->size);
    
            /* HACK/FIXME, we skip the initial 0-size packets as they are most likely equal to the encoder delay,
    
               but it would be better if we had the real timestamps from the encoder */
    
            if (frame_size >= 0 && (pkt->size || st->pts.num!=st->pts.den>>1 || st->pts.val)) {
    
                av_frac_add(&st->pts, (int64_t)st->time_base.den * frame_size);
    
            break;
        case CODEC_TYPE_VIDEO:
    
            av_frac_add(&st->pts, (int64_t)st->time_base.den * st->codec.frame_rate_base);
    
    }
    
    static void truncate_ts(AVStream *st, AVPacket *pkt){
        int64_t pts_mask = (2LL << (st->pts_wrap_bits-1)) - 1;
        
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    //    if(pkt->dts < 0)
    //        pkt->dts= 0;  //this happens for low_delay=0 and b frames, FIXME, needs further invstigation about what we should do here
    
        
        pkt->pts &= pts_mask;
        pkt->dts &= pts_mask;
    }
    
    /**
     * Write a packet to an output media file. The packet shall contain
     * one audio or video frame.
     *
     * @param s media file handle
     * @param pkt the packet, which contains the stream_index, buf/buf_size, dts/pts, ...
     * @return < 0 if error, = 0 if OK, 1 if end of stream wanted.
     */
    int av_write_frame(AVFormatContext *s, AVPacket *pkt)
    {
    
        compute_pkt_fields2(s->streams[pkt->stream_index], pkt);
        
        truncate_ts(s->streams[pkt->stream_index], pkt);
    
    
        ret= s->oformat->write_packet(s, pkt);
        if(!ret)
            ret= url_ferror(&s->pb);
        return ret;
    
    /**
     * interleave_packet implementation which will interleave per DTS.
     */
    static int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush){
        AVPacketList *pktl, **next_point, *this_pktl;
        int stream_count=0;
        int streams[MAX_STREAMS];
    
        if(pkt){
            AVStream *st= s->streams[ pkt->stream_index];
    
            assert(pkt->destruct != av_destruct_packet); //FIXME
    
            this_pktl = av_mallocz(sizeof(AVPacketList));
            this_pktl->pkt= *pkt;
            av_dup_packet(&this_pktl->pkt);
    
            next_point = &s->packet_buffer;
            while(*next_point){
                AVStream *st2= s->streams[ (*next_point)->pkt.stream_index];
                int64_t left=  st2->time_base.num * (int64_t)st ->time_base.den;
                int64_t right= st ->time_base.num * (int64_t)st2->time_base.den;
                if((*next_point)->pkt.dts * left > pkt->dts * right) //FIXME this can overflow
                    break;
                next_point= &(*next_point)->next;
            }
            this_pktl->next= *next_point;
            *next_point= this_pktl;
        }
        
        memset(streams, 0, sizeof(streams));
        pktl= s->packet_buffer;
        while(pktl){
    //av_log(s, AV_LOG_DEBUG, "show st:%d dts:%lld\n", pktl->pkt.stream_index, pktl->pkt.dts);
            if(streams[ pktl->pkt.stream_index ] == 0)
                stream_count++;
            streams[ pktl->pkt.stream_index ]++;
            pktl= pktl->next;
        }
        
        if(s->nb_streams == stream_count || (flush && stream_count)){
            pktl= s->packet_buffer;
            *out= pktl->pkt;
            
            s->packet_buffer= pktl->next;        
            av_freep(&pktl);
            return 1;
        }else{
            av_init_packet(out);
            return 0;
        }
    }
    
    /**
     * Interleaves a AVPacket correctly so it can be muxed.
     * @param out the interleaved packet will be output here
     * @param in the input packet
     * @param flush 1 if no further packets are available as input and all
     *              remaining packets should be output
     * @return 1 if a packet was output, 0 if no packet could be output, 
     *         < 0 if an error occured
     */
    static int av_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int flush){
        if(s->oformat->interleave_packet)
            return s->oformat->interleave_packet(s, out, in, flush);
        else
            return av_interleave_packet_per_dts(s, out, in, flush);
    }
    
    
    /**
     * Writes a packet to an output media file ensuring correct interleaving. 
     * The packet shall contain one audio or video frame.
     * If the packets are already correctly interleaved the application should
     * call av_write_frame() instead as its slightly faster, its also important
    
     * to keep in mind that completly non interleaved input will need huge amounts
    
     * of memory to interleave with this, so its prefereable to interleave at the
     * demuxer level
     *
     * @param s media file handle
     * @param pkt the packet, which contains the stream_index, buf/buf_size, dts/pts, ...
     * @return < 0 if error, = 0 if OK, 1 if end of stream wanted.
     */
    int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){
        AVStream *st= s->streams[ pkt->stream_index];
    
        compute_pkt_fields2(st, pkt);
    
        
        //FIXME/XXX/HACK drop zero sized packets
        if(st->codec.codec_type == CODEC_TYPE_AUDIO && pkt->size==0)
            return 0;
    
        if(pkt->dts == AV_NOPTS_VALUE)
            return -1;
    
    
        for(;;){
            AVPacket opkt;
            int ret= av_interleave_packet(s, &opkt, pkt, 0);
            if(ret<=0) //FIXME cleanup needed for ret<0 ?
                return ret;
    
            truncate_ts(s->streams[opkt.stream_index], &opkt);
            ret= s->oformat->write_packet(s, &opkt);
            
            av_free_packet(&opkt);
            pkt= NULL;
    
            if(url_ferror(&s->pb))
                return url_ferror(&s->pb);
    
    }
    
    /**
     * write the stream trailer to an output media file and and free the
     * file private data.
     *
     * @param s media file handle
     * @return 0 if OK. AVERROR_xxx if error.  */
    int av_write_trailer(AVFormatContext *s)
    {
    
        for(;;){
            AVPacket pkt;
            ret= av_interleave_packet(s, &pkt, NULL, 1);
            if(ret<0) //FIXME cleanup needed for ret<0 ?
    
            truncate_ts(s->streams[pkt.stream_index], &pkt);
            ret= s->oformat->write_packet(s, &pkt);
            
            av_free_packet(&pkt);
    
            if(url_ferror(&s->pb))
                goto fail;
    
        if(ret == 0)
           ret=url_ferror(&s->pb);
    
        for(i=0;i<s->nb_streams;i++)
            av_freep(&s->streams[i]->priv_data);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    }
    
    /* "user interface" functions */
    
    void dump_format(AVFormatContext *ic,
                     int index, 
                     const char *url,
                     int is_output)
    {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        char buf[256];
    
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
        av_log(NULL, AV_LOG_DEBUG, "%s #%d, %s, %s '%s':\n", 
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                is_output ? "Output" : "Input",
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                is_output ? "to" : "from", url);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_log(NULL, AV_LOG_DEBUG, "  Duration: ");
    
            if (ic->duration != AV_NOPTS_VALUE) {
                int hours, mins, secs, us;
                secs = ic->duration / AV_TIME_BASE;
                us = ic->duration % AV_TIME_BASE;
                mins = secs / 60;
                secs %= 60;
                hours = mins / 60;
                mins %= 60;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                av_log(NULL, AV_LOG_DEBUG, "%02d:%02d:%02d.%01d", hours, mins, secs, 
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                av_log(NULL, AV_LOG_DEBUG, "N/A");
    
            if (ic->start_time != AV_NOPTS_VALUE) {
                int secs, us;
                av_log(NULL, AV_LOG_DEBUG, ", start: ");
                secs = ic->start_time / AV_TIME_BASE;
                us = ic->start_time % AV_TIME_BASE;
                av_log(NULL, AV_LOG_DEBUG, "%d.%06d",
                       secs, (int)av_rescale(us, 1000000, AV_TIME_BASE));
            }
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_log(NULL, AV_LOG_DEBUG, ", bitrate: ");
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                av_log(NULL, AV_LOG_DEBUG,"%d kb/s", ic->bit_rate / 1000);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                av_log(NULL, AV_LOG_DEBUG, "N/A");
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_log(NULL, AV_LOG_DEBUG, "\n");
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        for(i=0;i<ic->nb_streams;i++) {
            AVStream *st = ic->streams[i];
            avcodec_string(buf, sizeof(buf), &st->codec, is_output);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_log(NULL, AV_LOG_DEBUG, "  Stream #%d.%d", index, i);
    
            /* the pid is an important information, so we display it */
            /* XXX: add a generic system */
            if (is_output)
                flags = ic->oformat->flags;
            else
                flags = ic->iformat->flags;
            if (flags & AVFMT_SHOW_IDS) {
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                av_log(NULL, AV_LOG_DEBUG, "[0x%x]", st->id);
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            av_log(NULL, AV_LOG_DEBUG, ": %s\n", buf);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    }
    
    typedef struct {
    
        const char *abv;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        int width, height;
    
        int frame_rate, frame_rate_base;
    } AbvEntry;
    
    static AbvEntry frame_abvs[] = {
    
        { "ntsc",      720, 480, 30000, 1001 },
        { "pal",       720, 576,    25,    1 },
        { "qntsc",     352, 240, 30000, 1001 }, /* VCD compliant ntsc */
        { "qpal",      352, 288,    25,    1 }, /* VCD compliant pal */
    
        { "sntsc",     640, 480, 30000, 1001 }, /* square pixel ntsc */
        { "spal",      768, 576,    25,    1 }, /* square pixel pal */
    
        { "film",      352, 240,    24,    1 },
        { "ntsc-film", 352, 240, 24000, 1001 },
        { "sqcif",     128,  96,     0,    0 },
        { "qcif",      176, 144,     0,    0 },
        { "cif",       352, 288,     0,    0 },
        { "4cif",      704, 576,     0,    0 },
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    };
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    int parse_image_size(int *width_ptr, int *height_ptr, const char *str)
    {
        int i;
    
        int n = sizeof(frame_abvs) / sizeof(AbvEntry);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        const char *p;
        int frame_width = 0, frame_height = 0;
    
        for(i=0;i<n;i++) {
    
            if (!strcmp(frame_abvs[i].abv, str)) {
                frame_width = frame_abvs[i].width;
                frame_height = frame_abvs[i].height;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                break;
            }
        }
        if (i == n) {
            p = str;
            frame_width = strtol(p, (char **)&p, 10);
            if (*p)
                p++;
            frame_height = strtol(p, (char **)&p, 10);
        }
        if (frame_width <= 0 || frame_height <= 0)
            return -1;
        *width_ptr = frame_width;
        *height_ptr = frame_height;
        return 0;
    }
    
    
    int parse_frame_rate(int *frame_rate, int *frame_rate_base, const char *arg)
    {
        int i;
        char* cp;
       
        /* First, we check our abbreviation table */
        for (i = 0; i < sizeof(frame_abvs)/sizeof(*frame_abvs); ++i)
             if (!strcmp(frame_abvs[i].abv, arg)) {
    	     *frame_rate = frame_abvs[i].frame_rate;
    	     *frame_rate_base = frame_abvs[i].frame_rate_base;
    	     return 0;
    	 }
    
        /* Then, we try to parse it as fraction */
        cp = strchr(arg, '/');
        if (cp) {
            char* cpp;
    	*frame_rate = strtol(arg, &cpp, 10);
    	if (cpp != arg || cpp == cp) 
    	    *frame_rate_base = strtol(cp+1, &cpp, 10);
    	else
    	   *frame_rate = 0;
        } 
        else {
            /* Finally we give up and parse it as double */
    
            *frame_rate_base = DEFAULT_FRAME_RATE_BASE; //FIXME use av_d2q()
    
            *frame_rate = (int)(strtod(arg, 0) * (*frame_rate_base) + 0.5);
        }
        if (!*frame_rate || !*frame_rate_base)
            return -1;
        else
            return 0;
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /* Syntax:
     * - If not a duration:
     *  [{YYYY-MM-DD|YYYYMMDD}]{T| }{HH[:MM[:SS[.m...]]][Z]|HH[MM[SS[.m...]]][Z]}
    
     * Time is localtime unless Z is suffixed to the end. In this case GMT
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     * Return the date in micro seconds since 1970 
     * - If duration:
     *  HH[:MM[:SS[.m...]]]
     *  S+[.m...]
     */
    
    int64_t parse_date(const char *datestr, int duration)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        const char *p;
    
        int64_t t;
    
        int i;
        static const char *date_fmt[] = {
            "%Y-%m-%d",
            "%Y%m%d",
        };
        static const char *time_fmt[] = {
            "%H:%M:%S",
            "%H%M%S",
        };
        const char *q;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        int is_utc, len;
    
        int negative = 0;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        len = strlen(datestr);
        if (len > 0)
            lastch = datestr[len - 1];
        else
            lastch = '\0';
    
        is_utc = (lastch == 'z' || lastch == 'Z');
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        p = datestr;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        q = NULL;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        if (!duration) {
    
            for (i = 0; i < sizeof(date_fmt) / sizeof(date_fmt[0]); i++) {
    
                q = small_strptime(p, date_fmt[i], &dt);
    
                if (q) {
                    break;
                }
            }
    
            if (!q) {
                if (is_utc) {
                    dt = *gmtime(&now);
                } else {
                    dt = *localtime(&now);
                }
                dt.tm_hour = dt.tm_min = dt.tm_sec = 0;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            } else {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            for (i = 0; i < sizeof(time_fmt) / sizeof(time_fmt[0]); i++) {
    
                q = small_strptime(p, time_fmt[i], &dt);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                if (q) {
                    break;
                }
            }
        } else {
    
    	if (p[0] == '-') {
    	    negative = 1;
    	    ++p;
    	}
    
            q = small_strptime(p, time_fmt[0], &dt);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            if (!q) {
                dt.tm_sec = strtol(p, (char **)&q, 10);
                dt.tm_min = 0;
                dt.tm_hour = 0;
    
            }
        }
    
        /* Now we have all the fields that we can get */
        if (!q) {
            if (duration)
                return 0;
            else
    
                return now * int64_t_C(1000000);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
            t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
    
            dt.tm_isdst = -1;       /* unknown */
            if (is_utc) {
                t = mktimegm(&dt);
            } else {
                t = mktime(&dt);
            }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            int val, n;
    
            q++;
            for (val = 0, n = 100000; n >= 1; n /= 10, q++) {
                if (!isdigit(*q)) 
                    break;
                val += n * (*q - '0');
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            }
            t += val;
        }
    
        return negative ? -t : t;
    
    /* syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. Return
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
       1 if found */
    int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
    {
        const char *p;
        char tag[128], *q;
    
        p = info;
        if (*p == '?')
            p++;
        for(;;) {
            q = tag;
            while (*p != '\0' && *p != '=' && *p != '&') {
                if ((q - tag) < sizeof(tag) - 1)
                    *q++ = *p;
                p++;
            }
            *q = '\0';
            q = arg;
            if (*p == '=') {
                p++;
                while (*p != '&' && *p != '\0') {
    
                    if ((q - arg) < arg_size - 1) {
                        if (*p == '+')
                            *q++ = ' ';
                        else
                            *q++ = *p;
                    }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    p++;
                }
                *q = '\0';
            }
            if (!strcmp(tag, tag1)) 
                return 1;
            if (*p != '&')
                break;
    
    /* Return in 'buf' the path with '%d' replaced by number. Also handles
       the '%0nd' format where 'n' is the total number of digits and
       '%%'. Return 0 if OK, and -1 if format error */
    int get_frame_filename(char *buf, int buf_size,
                           const char *path, int number)
    {
        const char *p;
    
    
        q = buf;
        p = path;
        percentd_found = 0;
        for(;;) {
            c = *p++;
            if (c == '\0')
                break;
            if (c == '%') {
    
                do {
                    nd = 0;
                    while (isdigit(*p)) {
                        nd = nd * 10 + *p++ - '0';
                    }
                    c = *p++;
                } while (isdigit(c));
    
    
                switch(c) {
                case '%':
                    goto addchar;
                case 'd':
                    if (percentd_found)
                        goto fail;
                    percentd_found = 1;
                    snprintf(buf1, sizeof(buf1), "%0*d", nd, number);
                    len = strlen(buf1);
                    if ((q - buf + len) > buf_size - 1)
                        goto fail;
                    memcpy(q, buf1, len);
                    q += len;
                    break;
                default:
                    goto fail;
                }
            } else {
            addchar:
                if ((q - buf) < buf_size - 1)
                    *q++ = c;
            }
        }
        if (!percentd_found)
            goto fail;
        *q = '\0';
        return 0;
     fail:
        *q = '\0';
        return -1;
    }
    
    
     * Print  nice hexa dump of a buffer
     * @param f stream for output
    
    void av_hex_dump(FILE *f, uint8_t *buf, int size)
    
    {
        int len, i, j, c;
    
        for(i=0;i<size;i+=16) {
            len = size - i;
            if (len > 16)
                len = 16;
    
            fprintf(f, "%08x ", i);
    
                    fprintf(f, " %02x", buf[i+j]);
    
    /**
     * Print on 'f' a nice dump of a packet
     * @param f stream for output
     * @param pkt packet to dump
     * @param dump_payload true if the payload must be displayed too
     */
    void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload)
    {
        fprintf(f, "stream #%d:\n", pkt->stream_index);
        fprintf(f, "  keyframe=%d\n", ((pkt->flags & PKT_FLAG_KEY) != 0));
        fprintf(f, "  duration=%0.3f\n", (double)pkt->duration / AV_TIME_BASE);
    
        /* DTS is _always_ valid after av_read_frame() */
        fprintf(f, "  dts=");
        if (pkt->dts == AV_NOPTS_VALUE)
            fprintf(f, "N/A");
        else
            fprintf(f, "%0.3f", (double)pkt->dts / AV_TIME_BASE);
    
        /* PTS may be not known if B frames are present */
        fprintf(f, "  pts=");
        if (pkt->pts == AV_NOPTS_VALUE)
            fprintf(f, "N/A");
        else
            fprintf(f, "%0.3f", (double)pkt->pts / AV_TIME_BASE);
        fprintf(f, "\n");
        fprintf(f, "  size=%d\n", pkt->size);
        if (dump_payload)
            av_hex_dump(f, pkt->data, pkt->size);
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    void url_split(char *proto, int proto_size,
    
                   char *authorization, int authorization_size,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                   char *hostname, int hostname_size,
                   int *port_ptr,
                   char *path, int path_size,
                   const char *url)
    {
        const char *p;
        char *q;
        int port;
    
        port = -1;
    
        p = url;
        q = proto;
        while (*p != ':' && *p != '\0') {
            if ((q - proto) < proto_size - 1)
                *q++ = *p;
            p++;
        }
        if (proto_size > 0)
            *q = '\0';
    
        if (authorization_size > 0)
            authorization[0] = '\0';
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        if (*p == '\0') {
            if (proto_size > 0)
                proto[0] = '\0';
            if (hostname_size > 0)
                hostname[0] = '\0';
            p = url;
        } else {
    
            char *at,*slash; // PETR: position of '@' character and '/' character
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            p++;
            if (*p == '/')
                p++;
            if (*p == '/')
                p++;
    
            at = strchr(p,'@'); // PETR: get the position of '@'
            slash = strchr(p,'/');  // PETR: get position of '/' - end of hostname
            if (at && slash && at > slash) at = NULL; // PETR: not interested in '@' behind '/'
    
            q = at ? authorization : hostname;  // PETR: if '@' exists starting with auth.
    
             while ((at || *p != ':') && *p != '/' && *p != '?' && *p != '\0') { // PETR:
                if (*p == '@') {    // PETR: passed '@'
                  if (authorization_size > 0)
                      *q = '\0';
                  q = hostname;
                  at = NULL;
                } else if (!at) {   // PETR: hostname
                  if ((q - hostname) < hostname_size - 1)
                      *q++ = *p;
                } else {
                  if ((q - authorization) < authorization_size - 1)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    *q++ = *p;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                p++;
            }
            if (hostname_size > 0)
                *q = '\0';
            if (*p == ':') {
                p++;
                port = strtoul(p, (char **)&p, 10);
            }
        }
        if (port_ptr)
            *port_ptr = port;
        pstrcpy(path, path_size, p);
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /**
     * Set the pts for a given stream
     * @param s stream 
     * @param pts_wrap_bits number of bits effectively used by the pts
     *        (used for wrap control, 33 is the value for MPEG) 
     * @param pts_num numerator to convert to seconds (MPEG: 1) 
     * @param pts_den denominator to convert to seconds (MPEG: 90000)
     */
    
    void av_set_pts_info(AVStream *s, int pts_wrap_bits,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                         int pts_num, int pts_den)
    {
        s->pts_wrap_bits = pts_wrap_bits;
    
        s->time_base.num = pts_num;
        s->time_base.den = pts_den;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    }
    
    /* fraction handling */
    
    /**
     * f = val + (num / den) + 0.5. 'num' is normalized so that it is such
     * as 0 <= num < den.
     *
     * @param f fractional number
     * @param val integer value
     * @param num must be >= 0
     * @param den must be >= 1 
     */
    
    void av_frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        num += (den >> 1);
        if (num >= den) {
            val += num / den;
            num = num % den;
        }
        f->val = val;
        f->num = num;
        f->den = den;
    }
    
    /* set f to (val + 0.5) */
    
    void av_frac_set(AVFrac *f, int64_t val)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        f->val = val;
        f->num = f->den >> 1;
    }
    
    /**
     * Fractionnal addition to f: f = f + (incr / f->den)
     *
     * @param f fractional number
     * @param incr increment, can be positive or negative
     */
    
    void av_frac_add(AVFrac *f, int64_t incr)
    
        int64_t num, den;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        num = f->num + incr;
        den = f->den;
        if (num < 0) {
            f->val += num / den;
            num = num % den;
            if (num < 0) {
                num += den;
                f->val--;
            }
        } else if (num >= den) {
            f->val += num / den;
            num = num % den;
        }
        f->num = num;
    }
    
    
    /**
     * register a new image format
     * @param img_fmt Image format descriptor
     */
    void av_register_image_format(AVImageFormat *img_fmt)
    {
        AVImageFormat **p;
    
        p = &first_image_format;
        while (*p != NULL) p = &(*p)->next;
        *p = img_fmt;
        img_fmt->next = NULL;
    }
    
    /* guess image format */
    AVImageFormat *av_probe_image_format(AVProbeData *pd)
    {
        AVImageFormat *fmt1, *fmt;
        int score, score_max;
    
        fmt = NULL;
        score_max = 0;
        for(fmt1 = first_image_format; fmt1 != NULL; fmt1 = fmt1->next) {
            if (fmt1->img_probe) {
                score = fmt1->img_probe(pd);
                if (score > score_max) {
                    score_max = score;
                    fmt = fmt1;
                }
            }
        }
        return fmt;
    }
    
    AVImageFormat *guess_image_format(const char *filename)
    {
        AVImageFormat *fmt1;
    
        for(fmt1 = first_image_format; fmt1 != NULL; fmt1 = fmt1->next) {
            if (fmt1->extensions && match_ext(filename, fmt1->extensions))
                return fmt1;
        }
        return NULL;
    }
    
    /**
     * Read an image from a stream. 
     * @param gb byte stream containing the image
     * @param fmt image format, NULL if probing is required
     */
    int av_read_image(ByteIOContext *pb, const char *filename,
                      AVImageFormat *fmt,
                      int (*alloc_cb)(void *, AVImageInfo *info), void *opaque)
    {
        char buf[PROBE_BUF_SIZE];
        AVProbeData probe_data, *pd = &probe_data;
        offset_t pos;
        int ret;
    
        if (!fmt) {
    
            pd->filename = filename;
    
            pd->buf = buf;
            pos = url_ftell(pb);
            pd->buf_size = get_buffer(pb, buf, PROBE_BUF_SIZE);
            url_fseek(pb, pos, SEEK_SET);
            fmt = av_probe_image_format(pd);
        }
        if (!fmt)
            return AVERROR_NOFMT;
        ret = fmt->img_read(pb, alloc_cb, opaque);
        return ret;
    }
    
    /**
     * Write an image to a stream.
     * @param pb byte stream for the image output
     * @param fmt image format
     * @param img image data and informations
     */
    int av_write_image(ByteIOContext *pb, AVImageFormat *fmt, AVImageInfo *img)
    {
        return fmt->img_write(pb, img);
    }