Newer
Older
Fabrice Bellard
committed
st->id = id;
Fabrice Bellard
committed
st->start_time = AV_NOPTS_VALUE;
st->duration = AV_NOPTS_VALUE;
st->cur_dts = AV_NOPTS_VALUE;
/* default pts settings is MPEG like */
av_set_pts_info(st, 33, 1, 90000);
Fabrice Bellard
committed
s->streams[s->nb_streams++] = st;
return st;
}
/************************************************************/
/* output media file */
int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap)
{
int ret;
if (s->oformat->priv_data_size > 0) {
s->priv_data = av_mallocz(s->oformat->priv_data_size);
if (!s->priv_data)
return AVERROR_NOMEM;
} else
s->priv_data = NULL;
if (s->oformat->set_parameters) {
ret = s->oformat->set_parameters(s, ap);
if (ret < 0)
return ret;
}
return 0;
}
Fabrice Bellard
committed
/**
* allocate the stream private data and write the stream header to an
* output media file
*
* @param s media file handle
* @return 0 if OK. AVERROR_xxx if error.
*/
int av_write_header(AVFormatContext *s)
{
int ret, i;
AVStream *st;
ret = s->oformat->write_header(s);
if (ret < 0)
return ret;
/* init PTS generation */
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
switch (st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
av_frac_init(&st->pts, 0, 0,
(int64_t)st->time_base.num * st->codec.sample_rate);
break;
case CODEC_TYPE_VIDEO:
av_frac_init(&st->pts, 0, 0,
(int64_t)st->time_base.num * st->codec.frame_rate);
break;
default:
break;
}
}
return 0;
Fabrice Bellard
committed
}
//FIXME merge with compute_pkt_fields
Michael Niedermayer
committed
static int compute_pkt_fields2(AVStream *st, AVPacket *pkt){
int b_frames = FFMAX(st->codec.has_b_frames, st->codec.max_b_frames);
int num, den, frame_size;
// av_log(NULL, AV_LOG_DEBUG, "av_write_frame: pts:%lld dts:%lld cur_dts:%lld b:%d size:%d st:%d\n", pkt->pts, pkt->dts, st->cur_dts, b_frames, pkt->size, pkt->stream_index);
/* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
return -1;*/
if(pkt->pts != AV_NOPTS_VALUE)
pkt->pts = av_rescale(pkt->pts, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num);
if(pkt->dts != AV_NOPTS_VALUE)
pkt->dts = av_rescale(pkt->dts, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num);
/* duration field */
pkt->duration = av_rescale(pkt->duration, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num);
if (pkt->duration == 0) {
compute_frame_duration(&num, &den, st, NULL, pkt);
if (den && num) {
pkt->duration = av_rescale(1, num * (int64_t)st->time_base.den, den * (int64_t)st->time_base.num);
}
}
//XXX/FIXME this is a temporary hack until all encoders output pts
if((pkt->pts == 0 || pkt->pts == AV_NOPTS_VALUE) && pkt->dts == AV_NOPTS_VALUE && !b_frames){
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;
}
Michael Niedermayer
committed
if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && st->cur_dts >= pkt->dts){
av_log(NULL, AV_LOG_ERROR, "error, non monotone timestamps %Ld >= %Ld\n", st->cur_dts, pkt->dts);
return -1;
}
if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts < pkt->dts){
av_log(NULL, AV_LOG_ERROR, "error, pts < dts\n");
return -1;
}
// 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);
Fabrice Bellard
committed
}
break;
case CODEC_TYPE_VIDEO:
av_frac_add(&st->pts, (int64_t)st->time_base.den * st->codec.frame_rate_base);
break;
default:
break;
}
Michael Niedermayer
committed
return 0;
}
static void truncate_ts(AVStream *st, AVPacket *pkt){
int64_t pts_mask = (2LL << (st->pts_wrap_bits-1)) - 1;
// 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)
{
Michael Niedermayer
committed
ret=compute_pkt_fields2(s->streams[pkt->stream_index], pkt);
if(ret<0)
return ret;
truncate_ts(s->streams[pkt->stream_index], pkt);
ret= s->oformat->write_packet(s, pkt);
if(!ret)
ret= url_ferror(&s->pb);
return ret;
Michael Niedermayer
committed
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
/**
* 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
Michael Niedermayer
committed
* 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];
Michael Niedermayer
committed
if(compute_pkt_fields2(st, pkt) < 0)
return -1;
//FIXME/XXX/HACK drop zero sized packets
if(st->codec.codec_type == CODEC_TYPE_AUDIO && pkt->size==0)
return 0;
Michael Niedermayer
committed
if(pkt->dts == AV_NOPTS_VALUE)
return -1;
Michael Niedermayer
committed
for(;;){
AVPacket opkt;
int ret= av_interleave_packet(s, &opkt, pkt, 0);
if(ret<=0) //FIXME cleanup needed for ret<0 ?
return ret;
Michael Niedermayer
committed
truncate_ts(s->streams[opkt.stream_index], &opkt);
ret= s->oformat->write_packet(s, &opkt);
av_free_packet(&opkt);
pkt= NULL;
if(ret<0)
return ret;
if(url_ferror(&s->pb))
return url_ferror(&s->pb);
Fabrice Bellard
committed
}
/**
* 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)
{
int ret, i;
Michael Niedermayer
committed
for(;;){
AVPacket pkt;
ret= av_interleave_packet(s, &pkt, NULL, 1);
if(ret<0) //FIXME cleanup needed for ret<0 ?
goto fail;
Michael Niedermayer
committed
if(!ret)
break;
Michael Niedermayer
committed
truncate_ts(s->streams[pkt.stream_index], &pkt);
ret= s->oformat->write_packet(s, &pkt);
av_free_packet(&pkt);
goto fail;
Fabrice Bellard
committed
ret = s->oformat->write_trailer(s);
for(i=0;i<s->nb_streams;i++)
av_freep(&s->streams[i]->priv_data);
Fabrice Bellard
committed
av_freep(&s->priv_data);
return ret;
}
/* "user interface" functions */
void dump_format(AVFormatContext *ic,
int index,
const char *url,
int is_output)
{
Fabrice Bellard
committed
int i, flags;
av_log(NULL, AV_LOG_DEBUG, "%s #%d, %s, %s '%s':\n",
Fabrice Bellard
committed
index,
is_output ? ic->oformat->name : ic->iformat->name,
Fabrice Bellard
committed
if (!is_output) {
Fabrice Bellard
committed
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;
av_log(NULL, AV_LOG_DEBUG, "%02d:%02d:%02d.%01d", hours, mins, secs,
Fabrice Bellard
committed
(10 * us) / AV_TIME_BASE);
} else {
Fabrice Bellard
committed
}
Wolfram Gloger
committed
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));
}
Fabrice Bellard
committed
if (ic->bit_rate) {
av_log(NULL, AV_LOG_DEBUG,"%d kb/s", ic->bit_rate / 1000);
Fabrice Bellard
committed
} else {
Fabrice Bellard
committed
}
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);
av_log(NULL, AV_LOG_DEBUG, " Stream #%d.%d", index, i);
Fabrice Bellard
committed
/* 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) {
Fabrice Bellard
committed
}
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 },
int parse_image_size(int *width_ptr, int *height_ptr, const char *str)
{
int i;
int n = sizeof(frame_abvs) / sizeof(AbvEntry);
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;
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;
}
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
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;
}
/* Syntax:
* - If not a duration:
* [{YYYY-MM-DD|YYYYMMDD}]{T| }{HH[:MM[:SS[.m...]]][Z]|HH[MM[SS[.m...]]][Z]}
Philip Gladstone
committed
* Time is localtime unless Z is suffixed to the end. In this case GMT
* 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)
Philip Gladstone
committed
struct tm dt;
Philip Gladstone
committed
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;
Philip Gladstone
committed
char lastch;
#undef time
Philip Gladstone
committed
time_t now = time(0);
len = strlen(datestr);
if (len > 0)
lastch = datestr[len - 1];
else
lastch = '\0';
Philip Gladstone
committed
is_utc = (lastch == 'z' || lastch == 'Z');
Philip Gladstone
committed
memset(&dt, 0, sizeof(dt));
Philip Gladstone
committed
for (i = 0; i < sizeof(date_fmt) / sizeof(date_fmt[0]); i++) {
Fabrice Bellard
committed
q = small_strptime(p, date_fmt[i], &dt);
Philip Gladstone
committed
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;
Philip Gladstone
committed
p = q;
Philip Gladstone
committed
if (*p == 'T' || *p == 't' || *p == ' ')
p++;
for (i = 0; i < sizeof(time_fmt) / sizeof(time_fmt[0]); i++) {
Fabrice Bellard
committed
q = small_strptime(p, time_fmt[i], &dt);
if (q) {
break;
}
}
} else {
if (p[0] == '-') {
negative = 1;
++p;
}
Fabrice Bellard
committed
q = small_strptime(p, time_fmt[0], &dt);
if (!q) {
dt.tm_sec = strtol(p, (char **)&q, 10);
dt.tm_min = 0;
dt.tm_hour = 0;
Philip Gladstone
committed
}
}
/* Now we have all the fields that we can get */
if (!q) {
if (duration)
return 0;
else
Philip Gladstone
committed
if (duration) {
Philip Gladstone
committed
t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
Philip Gladstone
committed
} else {
Philip Gladstone
committed
dt.tm_isdst = -1; /* unknown */
if (is_utc) {
t = mktimegm(&dt);
} else {
t = mktime(&dt);
}
Philip Gladstone
committed
Philip Gladstone
committed
t *= 1000000;
if (*q == '.') {
Philip Gladstone
committed
q++;
for (val = 0, n = 100000; n >= 1; n /= 10, q++) {
if (!isdigit(*q))
break;
val += n * (*q - '0');
Philip Gladstone
committed
/* syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. Return
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
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') {
Philip Gladstone
committed
if ((q - arg) < arg_size - 1) {
if (*p == '+')
*q++ = ' ';
else
*q++ = *p;
}
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;
Panagiotis Issaris
committed
char *q, buf1[20], c;
int nd, len, percentd_found;
q = buf;
p = path;
percentd_found = 0;
for(;;) {
c = *p++;
if (c == '\0')
break;
if (c == '%') {
Philip Gladstone
committed
do {
nd = 0;
while (isdigit(*p)) {
nd = nd * 10 + *p++ - '0';
}
c = *p++;
} while (isdigit(c));
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
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;
}
Fabrice Bellard
committed
/**
* Print nice hexa dump of a buffer
* @param f stream for output
Fabrice Bellard
committed
* @param buf buffer
* @param size buffer size
*/
void av_hex_dump(FILE *f, uint8_t *buf, int size)
Fabrice Bellard
committed
{
int len, i, j, c;
for(i=0;i<size;i+=16) {
len = size - i;
if (len > 16)
len = 16;
fprintf(f, "%08x ", i);
Fabrice Bellard
committed
for(j=0;j<16;j++) {
if (j < len)
fprintf(f, " %02x", buf[i+j]);
Fabrice Bellard
committed
else
Fabrice Bellard
committed
}
Fabrice Bellard
committed
for(j=0;j<len;j++) {
c = buf[i+j];
if (c < ' ' || c > '~')
c = '.';
fprintf(f, "%c", c);
Fabrice Bellard
committed
}
fprintf(f, "\n");
Fabrice Bellard
committed
}
}
/**
* 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);
}
Petr Doubek
committed
char *authorization, int authorization_size,
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';
Petr Doubek
committed
if (authorization_size > 0)
authorization[0] = '\0';
if (*p == '\0') {
if (proto_size > 0)
proto[0] = '\0';
if (hostname_size > 0)
hostname[0] = '\0';
p = url;
} else {
Petr Doubek
committed
char *at,*slash; // PETR: position of '@' character and '/' character
p++;
if (*p == '/')
p++;
if (*p == '/')
p++;
Petr Doubek
committed
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)
Petr Doubek
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);
}
/**
* 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,
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;
}
/* 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)
{
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)
{
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)
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;
}
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
/**
* 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) {
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
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);
}