Newer
Older
* various utility functions for use within Libav
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* This file is part of Libav.
Diego Biurrun
committed
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
Diego Biurrun
committed
* version 2.1 of the License, or (at your option) any later version.
* Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/* #define DEBUG */
#include "avio_internal.h"
Ronald S. Bultje
committed
#include "internal.h"
#include "libavcodec/internal.h"
#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "libavutil/pixdesc.h"
#include "id3v2.h"
#include "libavutil/avstring.h"
#include "libavutil/mathematics.h"
#include "riff.h"
#include "url.h"
#include <sys/time.h>
#include <time.h>
#include <stdarg.h>
#if CONFIG_NETWORK
#include "network.h"
#endif
Philip Gladstone
committed
#undef NDEBUG
#include <assert.h>
Daniel Kristjansson
committed
/**
* various utility functions for use within Libav
Daniel Kristjansson
committed
*/
unsigned avformat_version(void)
{
return LIBAVFORMAT_VERSION_INT;
}
const char *avformat_configuration(void)
return LIBAV_CONFIGURATION;
const char *avformat_license(void)
{
#define LICENSE_PREFIX "libavformat license: "
return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
Stefano Sabatini
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
*/
static void frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den)
Stefano Sabatini
committed
{
num += (den >> 1);
if (num >= den) {
val += num / den;
num = num % den;
}
f->val = val;
f->num = num;
f->den = den;
}
/**
* Fractional addition to f: f = f + (incr / f->den).
*
* @param f fractional number
* @param incr increment, can be positive or negative
*/
static void frac_add(AVFrac *f, int64_t incr)
Stefano Sabatini
committed
{
int64_t num, den;
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;
}
/** head of registered input format linked list */
static AVInputFormat *first_iformat = NULL;
/** head of registered output format linked list */
static AVOutputFormat *first_oformat = NULL;
AVInputFormat *av_iformat_next(AVInputFormat *f)
{
if(f) return f->next;
else return first_iformat;
}
AVOutputFormat *av_oformat_next(AVOutputFormat *f)
{
if(f) return f->next;
else return first_oformat;
}
Fabrice Bellard
committed
void av_register_input_format(AVInputFormat *format)
Fabrice Bellard
committed
AVInputFormat **p;
p = &first_iformat;
while (*p != NULL) p = &(*p)->next;
*p = format;
format->next = NULL;
}
void av_register_output_format(AVOutputFormat *format)
{
AVOutputFormat **p;
p = &first_oformat;
while (*p != NULL) p = &(*p)->next;
*p = format;
format->next = NULL;
}
int av_match_ext(const char *filename, const char *extensions)
{
const char *ext, *p;
char ext1[32], *q;
ext = strrchr(filename, '.');
if (ext) {
ext++;
p = extensions;
for(;;) {
q = ext1;
while (*p != '\0' && *p != ',' && q-ext1<sizeof(ext1)-1)
static int match_format(const char *name, const char *names)
{
const char *p;
int len, namelen;
if (!name || !names)
return 0;
namelen = strlen(name);
while ((p = strchr(names, ','))) {
len = FFMAX(p - names, namelen);
if (!strncasecmp(name, names, len))
return 1;
names = p+1;
}
return !strcasecmp(name, names);
}
AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
const char *mime_type)
AVOutputFormat *fmt = NULL, *fmt_found;
#if CONFIG_IMAGE2_MUXER
if (!short_name && filename &&
Michel Bardiaux
committed
av_filename_number_test(filename) &&
ff_guess_image2_codec(filename) != CODEC_ID_NONE) {
return av_guess_format("image2", NULL, NULL);
while ((fmt = av_oformat_next(fmt))) {
score = 0;
if (fmt->name && short_name && !strcmp(fmt->name, short_name))
score += 100;
if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
score += 10;
if (filename && fmt->extensions &&
av_match_ext(filename, fmt->extensions)) {
score += 5;
}
if (score > score_max) {
score_max = score;
fmt_found = fmt;
}
}
return fmt_found;
enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
const char *filename, const char *mime_type, enum AVMediaType type){
if(type == AVMEDIA_TYPE_VIDEO){
enum CodecID codec_id= CODEC_ID_NONE;
#if CONFIG_IMAGE2_MUXER
if(!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")){
codec_id= ff_guess_image2_codec(filename);
if(codec_id == CODEC_ID_NONE)
codec_id= fmt->video_codec;
return codec_id;
}else if(type == AVMEDIA_TYPE_AUDIO)
else if (type == AVMEDIA_TYPE_SUBTITLE)
return fmt->subtitle_codec;
else
return CODEC_ID_NONE;
}
Fabrice Bellard
committed
AVInputFormat *av_find_input_format(const char *short_name)
{
AVInputFormat *fmt = NULL;
while ((fmt = av_iformat_next(fmt))) {
if (match_format(short_name, fmt->name))
Fabrice Bellard
committed
return fmt;
}
return NULL;
}
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
{
int ret= av_new_packet(pkt, size);
if(ret<0)
return ret;
pkt->pos= avio_tell(s);
ret= avio_read(s, pkt->data, size);
Reimar Döffinger
committed
av_shrink_packet(pkt, ret);
int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
{
int ret;
int old_size;
if (!pkt->size)
return av_get_packet(s, pkt, size);
old_size = pkt->size;
ret = av_grow_packet(pkt, size);
if (ret < 0)
return ret;
ret = avio_read(s, pkt->data + old_size, size);
av_shrink_packet(pkt, old_size + FFMAX(ret, 0));
return ret;
}
Michel Bardiaux
committed
int av_filename_number_test(const char *filename)
Fabrice Bellard
committed
{
char buf[1024];
Michel Bardiaux
committed
return filename && (av_get_frame_filename(buf, sizeof(buf), filename, 1)>=0);
Fabrice Bellard
committed
}
AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max)
Fabrice Bellard
committed
{
AVProbeData lpd = *pd;
AVInputFormat *fmt1 = NULL, *fmt;
int score, id3 = 0;
Fabrice Bellard
committed
if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
int id3len = ff_id3v2_tag_len(lpd.buf);
if (lpd.buf_size > id3len + 16) {
lpd.buf += id3len;
lpd.buf_size -= id3len;
}
id3 = 1;
}
Fabrice Bellard
committed
fmt = NULL;
while ((fmt1 = av_iformat_next(fmt1))) {
Reimar Döffinger
committed
if (!is_opened == !(fmt1->flags & AVFMT_NOFILE))
Fabrice Bellard
committed
continue;
score = 0;
Philip Gladstone
committed
if (fmt1->read_probe) {
score = fmt1->read_probe(&lpd);
Philip Gladstone
committed
} else if (fmt1->extensions) {
if (av_match_ext(lpd.filename, fmt1->extensions)) {
Fabrice Bellard
committed
score = 50;
}
Michael Niedermayer
committed
if (score > *score_max) {
*score_max = score;
Fabrice Bellard
committed
fmt = fmt1;
}else if (score == *score_max)
fmt = NULL;
Fabrice Bellard
committed
}
/* a hack for files with huge id3v2 tags -- try to guess by file extension. */
if (!fmt && id3 && *score_max < AVPROBE_SCORE_MAX/4) {
while ((fmt = av_iformat_next(fmt)))
if (fmt->extensions && av_match_ext(lpd.filename, fmt->extensions)) {
*score_max = AVPROBE_SCORE_MAX/4;
break;
}
}
Fabrice Bellard
committed
return fmt;
}
Michael Niedermayer
committed
AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened){
int score=0;
return av_probe_input_format2(pd, is_opened, &score);
}
static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd, int score)
Michael Niedermayer
committed
{
static const struct {
const char *name; enum CodecID id; enum AVMediaType type;
} fmt_id_type[] = {
{ "aac" , CODEC_ID_AAC , AVMEDIA_TYPE_AUDIO },
{ "ac3" , CODEC_ID_AC3 , AVMEDIA_TYPE_AUDIO },
{ "dts" , CODEC_ID_DTS , AVMEDIA_TYPE_AUDIO },
{ "eac3" , CODEC_ID_EAC3 , AVMEDIA_TYPE_AUDIO },
{ "h264" , CODEC_ID_H264 , AVMEDIA_TYPE_VIDEO },
{ "m4v" , CODEC_ID_MPEG4 , AVMEDIA_TYPE_VIDEO },
{ "mp3" , CODEC_ID_MP3 , AVMEDIA_TYPE_AUDIO },
{ "mpegvideo", CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO },
{ 0 }
};
AVInputFormat *fmt = av_probe_input_format2(pd, 1, &score);
Michael Niedermayer
committed
if (fmt) {
int i;
av_log(s, AV_LOG_DEBUG, "Probe with size=%d, packets=%d detected %s with score=%d\n",
pd->buf_size, MAX_PROBE_PACKETS - st->probe_packets, fmt->name, score);
for (i = 0; fmt_id_type[i].name; i++) {
if (!strcmp(fmt->name, fmt_id_type[i].name)) {
st->codec->codec_id = fmt_id_type[i].id;
st->codec->codec_type = fmt_id_type[i].type;
break;
}
Michael Niedermayer
committed
}
return !!fmt;
}
Fabrice Bellard
committed
/************************************************************/
/* input media file */
#if FF_API_FORMAT_PARAMETERS
static AVDictionary *convert_format_parameters(AVFormatParameters *ap)
{
char buf[1024];
AVDictionary *opts = NULL;
if (!ap)
return NULL;
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
if (ap->time_base.num) {
snprintf(buf, sizeof(buf), "%d/%d", ap->time_base.den, ap->time_base.num);
av_dict_set(&opts, "framerate", buf, 0);
}
if (ap->sample_rate) {
snprintf(buf, sizeof(buf), "%d", ap->sample_rate);
av_dict_set(&opts, "sample_rate", buf, 0);
}
if (ap->channels) {
snprintf(buf, sizeof(buf), "%d", ap->channels);
av_dict_set(&opts, "channels", buf, 0);
}
if (ap->width || ap->height) {
snprintf(buf, sizeof(buf), "%dx%d", ap->width, ap->height);
av_dict_set(&opts, "video_size", buf, 0);
}
if (ap->pix_fmt != PIX_FMT_NONE) {
av_dict_set(&opts, "pixel_format", av_get_pix_fmt_name(ap->pix_fmt), 0);
}
if (ap->channel) {
snprintf(buf, sizeof(buf), "%d", ap->channel);
av_dict_set(&opts, "channel", buf, 0);
}
if (ap->standard) {
av_dict_set(&opts, "standard", ap->standard, 0);
}
if (ap->mpeg2ts_compute_pcr) {
av_dict_set(&opts, "mpeg2ts_compute_pcr", "1", 0);
}
if (ap->initial_pause) {
av_dict_set(&opts, "initial_pause", "1", 0);
}
return opts;
}
Daniel Kristjansson
committed
* Open a media file from an IO stream. 'fmt' must be specified.
int av_open_input_stream(AVFormatContext **ic_ptr,
AVIOContext *pb, const char *filename,
AVInputFormat *fmt, AVFormatParameters *ap)
{
int err;
AVFormatContext *ic;
AVFormatParameters default_ap;
if(!ap){
ap=&default_ap;
memset(ap, 0, sizeof(default_ap));
}
opts = convert_format_parameters(ap);
if(!ap->prealloced_context)
ic = avformat_alloc_context();
if (!ic) {
err = AVERROR(ENOMEM);
goto fail;
}
Anton Khirnov
committed
if (pb && fmt && fmt->flags & AVFMT_NOFILE)
av_log(ic, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
"will be ignored with AVFMT_NOFILE format.\n");
else
ic->pb = pb;
if ((err = avformat_open_input(&ic, filename, fmt, &opts)) < 0)
goto fail;
Anton Khirnov
committed
ic->pb = ic->pb ? ic->pb : pb; // don't leak custom pb if it wasn't set above
fail:
av_dict_free(&opts);
return err;
}
/** size of probe buffer, for guessing file type from file contents */
#define PROBE_BUF_MIN 2048
#define PROBE_BUF_MAX (1<<20)
Fabrice Bellard
committed
int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
const char *filename, void *logctx,
unsigned int offset, unsigned int max_probe_size)
{
AVProbeData pd = { filename ? filename : "", NULL, -offset };
unsigned char *buf = NULL;
int ret = 0, probe_size;
if (!max_probe_size) {
max_probe_size = PROBE_BUF_MAX;
} else if (max_probe_size > PROBE_BUF_MAX) {
max_probe_size = PROBE_BUF_MAX;
} else if (max_probe_size < PROBE_BUF_MIN) {
return AVERROR(EINVAL);
}
if (offset >= max_probe_size) {
return AVERROR(EINVAL);
}
for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt && ret >= 0;
probe_size = FFMIN(probe_size<<1, FFMAX(max_probe_size, probe_size+1))) {
int ret, score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX/4 : 0;
int buf_offset = (probe_size == PROBE_BUF_MIN) ? 0 : probe_size>>1;
if (probe_size < offset) {
continue;
}
/* read probe data */
buf = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE);
if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) {
/* fail if error was not end of file, otherwise, lower score */
if (ret != AVERROR_EOF) {
av_free(buf);
return ret;
}
score = 0;
ret = 0; /* error was end of file, nothing read */
}
pd.buf_size += ret;
pd.buf = &buf[offset];
memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);
/* guess file format */
*fmt = av_probe_input_format2(&pd, 1, &score);
if(*fmt){
if(score <= AVPROBE_SCORE_MAX/4){ //this can only be true in the last iteration
av_log(logctx, AV_LOG_WARNING, "Format detected only with low score of %d, misdetection possible!\n", score);
}else
av_log(logctx, AV_LOG_DEBUG, "Probed with size=%d and score=%d\n", probe_size, score);
}
}
if (!*fmt) {
return AVERROR_INVALIDDATA;
}
/* rewind. reuse probe buffer to avoid seeking */
if ((ret = ffio_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0)
}
#if FF_API_FORMAT_PARAMETERS
int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
Fabrice Bellard
committed
AVInputFormat *fmt,
int buf_size,
AVFormatParameters *ap)
int err;
AVDictionary *opts = convert_format_parameters(ap);
if (!ap || !ap->prealloced_context)
Fabrice Bellard
committed
err = avformat_open_input(ic_ptr, filename, fmt, &opts);
Fabrice Bellard
committed
return err;
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
/* open input file and probe the format if necessary */
static int init_input(AVFormatContext *s, const char *filename)
{
int ret;
AVProbeData pd = {filename, NULL, 0};
if (s->pb) {
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if (!s->iformat)
return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0);
else if (s->iformat->flags & AVFMT_NOFILE)
return AVERROR(EINVAL);
return 0;
}
if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
(!s->iformat && (s->iformat = av_probe_input_format(&pd, 0))))
return 0;
if ((ret = avio_open(&s->pb, filename, AVIO_FLAG_READ)) < 0)
return ret;
if (s->iformat)
return 0;
return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0);
}
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
{
AVFormatContext *s = *ps;
int ret = 0;
AVFormatParameters ap = { { 0 } };
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
AVDictionary *tmp = NULL;
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
if (fmt)
s->iformat = fmt;
if (options)
av_dict_copy(&tmp, *options, 0);
if ((ret = av_opt_set_dict(s, &tmp)) < 0)
goto fail;
if ((ret = init_input(s, filename)) < 0)
goto fail;
/* check filename in case an image number is expected */
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
if (!av_filename_number_test(filename)) {
ret = AVERROR(EINVAL);
goto fail;
}
}
s->duration = s->start_time = AV_NOPTS_VALUE;
av_strlcpy(s->filename, filename, sizeof(s->filename));
/* allocate private data */
if (s->iformat->priv_data_size > 0) {
if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
ret = AVERROR(ENOMEM);
goto fail;
}
if (s->iformat->priv_class) {
*(const AVClass**)s->priv_data = s->iformat->priv_class;
av_opt_set_defaults(s->priv_data);
if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
goto fail;
}
}
/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
if (s->pb)
ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC);
if (s->iformat->read_header)
if ((ret = s->iformat->read_header(s, &ap)) < 0)
goto fail;
if (s->pb && !s->data_offset)
s->data_offset = avio_tell(s->pb);
s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
if (options) {
av_dict_free(options);
*options = tmp;
}
*ps = s;
return 0;
fail:
av_dict_free(&tmp);
if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
avio_close(s->pb);
avformat_free_context(s);
*ps = NULL;
return ret;
}
/*******************************************************/
static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
AVPacketList **plast_pktl){
AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
Michael Niedermayer
committed
if (!pktl)
return NULL;
if (*packet_buffer)
(*plast_pktl)->next = pktl;
else
*packet_buffer = pktl;
Michael Niedermayer
committed
/* add the packet in the buffered packet list */
*plast_pktl = pktl;
pktl->pkt= *pkt;
return &pktl->pkt;
}
int av_read_packet(AVFormatContext *s, AVPacket *pkt)
int ret, i;
for(;;){
AVPacketList *pktl = s->raw_packet_buffer;
if (pktl) {
*pkt = pktl->pkt;
if(s->streams[pkt->stream_index]->codec->codec_id != CODEC_ID_PROBE ||
!s->streams[pkt->stream_index]->probe_packets ||
s->raw_packet_buffer_remaining_size < pkt->size){
AVProbeData *pd = &s->streams[pkt->stream_index]->probe_data;
av_freep(&pd->buf);
pd->buf_size = 0;
s->raw_packet_buffer = pktl->next;
s->raw_packet_buffer_remaining_size += pkt->size;
av_free(pktl);
return 0;
}
}
av_init_packet(pkt);
ret= s->iformat->read_packet(s, pkt);
if (ret < 0) {
if (!pktl || ret == AVERROR(EAGAIN))
return ret;
for (i = 0; i < s->nb_streams; i++)
s->streams[i]->probe_packets = 0;
continue;
}
case AVMEDIA_TYPE_VIDEO:
if(s->video_codec_id) st->codec->codec_id= s->video_codec_id;
break;
case AVMEDIA_TYPE_AUDIO:
if(s->audio_codec_id) st->codec->codec_id= s->audio_codec_id;
break;
case AVMEDIA_TYPE_SUBTITLE:
if(s->subtitle_codec_id)st->codec->codec_id= s->subtitle_codec_id;
break;
}
if(!pktl && (st->codec->codec_id != CODEC_ID_PROBE ||
!st->probe_packets))
return ret;
add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);
s->raw_packet_buffer_remaining_size -= pkt->size;
if(st->codec->codec_id == CODEC_ID_PROBE){
AVProbeData *pd = &st->probe_data;
av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index);
--st->probe_packets;
pd->buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
memcpy(pd->buf+pd->buf_size, pkt->data, pkt->size);
pd->buf_size += pkt->size;
memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE);
Michael Niedermayer
committed
if(av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){
Michael Niedermayer
committed
//FIXME we dont reduce score to 0 for the case of running out of buffer space in bytes
set_codec_from_probe_data(s, st, pd, st->probe_packets > 0 ? AVPROBE_SCORE_MAX/4 : 0);
if(st->codec->codec_id != CODEC_ID_PROBE){
pd->buf_size=0;
av_freep(&pd->buf);
av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
Michael Niedermayer
committed
}
}
/**********************************************************/
Daniel Kristjansson
committed
/**
* Get the number of samples of an audio frame. Return -1 on error.
Daniel Kristjansson
committed
*/
static int get_audio_frame_size(AVCodecContext *enc, int size)
{
int frame_size;
Michael Niedermayer
committed
if(enc->codec_id == CODEC_ID_VORBIS)
return -1;
if (enc->frame_size <= 1) {
int bits_per_sample = av_get_bits_per_sample(enc->codec_id);
if (bits_per_sample) {
if (enc->channels == 0)
return -1;
frame_size = (size << 3) / (bits_per_sample * enc->channels);
/* used for example by ADPCM codecs */
if (enc->bit_rate == 0)
return -1;
frame_size = ((int64_t)size * 8 * enc->sample_rate) / enc->bit_rate;
}
} else {
frame_size = enc->frame_size;
}
return frame_size;
}
Daniel Kristjansson
committed
/**
* Return the frame duration in seconds. Return 0 if not available.
Daniel Kristjansson
committed
*/
static void compute_frame_duration(int *pnum, int *pden, AVStream *st,
AVCodecParserContext *pc, AVPacket *pkt)
{
int frame_size;
*pnum = 0;
*pden = 0;
Michael Niedermayer
committed
switch(st->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
*pnum = st->time_base.num;
*pden = st->time_base.den;
Michael Niedermayer
committed
}else if(st->codec->time_base.num*1000LL > st->codec->time_base.den){
*pnum = st->codec->time_base.num;
*pden = st->codec->time_base.den;
if (pc && pc->repeat_pict) {
*pnum = (*pnum) * (1 + pc->repeat_pict);
Michael Niedermayer
committed
//If this codec can be interlaced or progressive then we need a parser to compute duration of a packet
//Thus if we have no parser in such case leave duration undefined.
if(st->codec->ticks_per_frame>1 && !pc){
*pnum = *pden = 0;
}
case AVMEDIA_TYPE_AUDIO:
Michael Niedermayer
committed
frame_size = get_audio_frame_size(st->codec, pkt->size);
if (frame_size <= 0 || st->codec->sample_rate <= 0)
break;
*pnum = frame_size;
Michael Niedermayer
committed
*pden = st->codec->sample_rate;
break;
default:
break;
}
}
Michael Niedermayer
committed
static int is_intra_only(AVCodecContext *enc){
if(enc->codec_type == AVMEDIA_TYPE_AUDIO){
Michael Niedermayer
committed
return 1;
}else if(enc->codec_type == AVMEDIA_TYPE_VIDEO){
Michael Niedermayer
committed
switch(enc->codec_id){
case CODEC_ID_MJPEG:
case CODEC_ID_MJPEGB:
case CODEC_ID_LJPEG:
case CODEC_ID_RAWVIDEO:
case CODEC_ID_DVVIDEO:
case CODEC_ID_HUFFYUV:
Michael Niedermayer
committed
case CODEC_ID_ASV1:
case CODEC_ID_ASV2:
case CODEC_ID_VCR1:
Michael Niedermayer
committed
return 1;
default: break;
}
}
return 0;
}
static void update_initial_timestamps(AVFormatContext *s, int stream_index,
int64_t dts, int64_t pts)
{
AVStream *st= s->streams[stream_index];
AVPacketList *pktl= s->packet_buffer;
if(st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE || st->cur_dts == AV_NOPTS_VALUE)
return;
st->first_dts= dts - st->cur_dts;
st->cur_dts= dts;
for(; pktl; pktl= pktl->next){
if(pktl->pkt.stream_index != stream_index)
continue;
//FIXME think more about this check
if(pktl->pkt.pts != AV_NOPTS_VALUE && pktl->pkt.pts == pktl->pkt.dts)
pktl->pkt.pts += st->first_dts;
if(pktl->pkt.dts != AV_NOPTS_VALUE)
pktl->pkt.dts += st->first_dts;
Michael Niedermayer
committed
if(st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE)
st->start_time= pktl->pkt.pts;
if (st->start_time == AV_NOPTS_VALUE)
st->start_time = pts;
Michael Niedermayer
committed
static void update_initial_durations(AVFormatContext *s, AVStream *st, AVPacket *pkt)
{
AVPacketList *pktl= s->packet_buffer;
int64_t cur_dts= 0;
if(st->first_dts != AV_NOPTS_VALUE){
cur_dts= st->first_dts;
for(; pktl; pktl= pktl->next){
if(pktl->pkt.stream_index == pkt->stream_index){
if(pktl->pkt.pts != pktl->pkt.dts || pktl->pkt.dts != AV_NOPTS_VALUE || pktl->pkt.duration)
break;
cur_dts -= pkt->duration;
}
}
pktl= s->packet_buffer;
st->first_dts = cur_dts;
}else if(st->cur_dts)
return;
Michael Niedermayer
committed
for(; pktl; pktl= pktl->next){
if(pktl->pkt.stream_index != pkt->stream_index)
continue;
if(pktl->pkt.pts == pktl->pkt.dts && pktl->pkt.dts == AV_NOPTS_VALUE
&& !pktl->pkt.duration){
pktl->pkt.dts= cur_dts;
if(!st->codec->has_b_frames)
pktl->pkt.pts= cur_dts;
cur_dts += pkt->duration;
Michael Niedermayer
committed
pktl->pkt.duration= pkt->duration;
}else
break;
}
if(st->first_dts == AV_NOPTS_VALUE)
st->cur_dts= cur_dts;
Michael Niedermayer
committed
}
static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
AVCodecParserContext *pc, AVPacket *pkt)
{
int num, den, presentation_delayed, delay, i;
if (s->flags & AVFMT_FLAG_NOFILLIN)
return;
if((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE)
pkt->dts= AV_NOPTS_VALUE;
if (st->codec->codec_id != CODEC_ID_H264 && pc && pc->pict_type == AV_PICTURE_TYPE_B)
//FIXME Set low_delay = 0 when has_b_frames = 1
st->codec->has_b_frames = 1;
/* do we have a video B-frame ? */
delay= st->codec->has_b_frames;
presentation_delayed = 0;
// ignore delay caused by frame threading so that the mpeg2-without-dts
// warning will not trigger
if (delay && st->codec->active_thread_type&FF_THREAD_FRAME)
delay -= st->codec->thread_count-1;
/* XXX: need has_b_frame, but cannot get it if the codec is
not initialized */
if (delay &&
pc && pc->pict_type != AV_PICTURE_TYPE_B)
presentation_delayed = 1;
Michael Niedermayer
committed
if(pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && pkt->dts > pkt->pts && st->pts_wrap_bits<63
/*&& pkt->dts-(1LL<<st->pts_wrap_bits) < pkt->pts*/){
pkt->dts -= 1LL<<st->pts_wrap_bits;
}
Michael Niedermayer
committed
// some mpeg2 in mpeg-ps lack dts (issue171 / input_file.mpg)
// we take the conservative approach and discard both
// Note, if this is misbehaving for a H.264 file then possibly presentation_delayed is not set correctly.
if(delay==1 && pkt->dts == pkt->pts && pkt->dts != AV_NOPTS_VALUE && presentation_delayed){
av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination\n");
Michael Niedermayer
committed
pkt->dts= pkt->pts= AV_NOPTS_VALUE;
}
if (pkt->duration == 0) {
compute_frame_duration(&num, &den, st, pc, pkt);
pkt->duration = av_rescale_rnd(1, num * (int64_t)st->time_base.den, den * (int64_t)st->time_base.num, AV_ROUND_DOWN);
Michael Niedermayer
committed
if(pkt->duration != 0 && s->packet_buffer)
Michael Niedermayer
committed
update_initial_durations(s, st, pkt);
/* correct timestamps with byte offset if demuxers only have timestamps
on packet boundaries */
if(pc && st->need_parsing == AVSTREAM_PARSE_TIMESTAMPS && pkt->size){
/* this will estimate bitrate based on this frame's duration and size */
offset = av_rescale(pc->offset, pkt->duration, pkt->size);
if(pkt->pts != AV_NOPTS_VALUE)
pkt->pts += offset;
if(pkt->dts != AV_NOPTS_VALUE)
pkt->dts += offset;
}
if (pc && pc->dts_sync_point >= 0) {
// we have synchronization info from the parser
int64_t den = st->codec->time_base.den * (int64_t) st->time_base.num;
if (den > 0) {
int64_t num = st->codec->time_base.num * (int64_t) st->time_base.den;
if (pkt->dts != AV_NOPTS_VALUE) {
// got DTS from the stream, update reference timestamp
st->reference_dts = pkt->dts - pc->dts_ref_dts_delta * num / den;
pkt->pts = pkt->dts + pc->pts_dts_delta * num / den;