Newer
Older
* various utility functions for use within FFmpeg
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
Diego Biurrun
committed
* This file is part of FFmpeg.
*
* FFmpeg 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.
Diego Biurrun
committed
* FFmpeg 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
Diego Biurrun
committed
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
#include "libavutil/thread.h"
#include "libavutil/time_internal.h"
#include "libavutil/timestamp.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/internal.h"
#include "libavcodec/raw.h"
#include "avformat.h"
#include "avio_internal.h"
#include "id3v2.h"
#include "internal.h"
#include "metadata.h"
#if CONFIG_NETWORK
#include "network.h"
#endif
#include "riff.h"
#include "url.h"
#include "libavutil/ffversion.h"
const char av_format_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
static AVMutex avformat_mutex = AV_MUTEX_INITIALIZER;
Daniel Kristjansson
committed
/**
* various utility functions for use within FFmpeg
Daniel Kristjansson
committed
*/
av_assert0(LIBAVFORMAT_VERSION_MICRO >= 100);
const char *avformat_configuration(void)
return FFMPEG_CONFIGURATION;
const char *avformat_license(void)
{
#define LICENSE_PREFIX "libavformat license: "
return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
int ff_lock_avformat(void)
{
return ff_mutex_lock(&avformat_mutex) ? -1 : 0;
}
int ff_unlock_avformat(void)
{
return ff_mutex_unlock(&avformat_mutex) ? -1 : 0;
}
#define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48))
static int is_relative(int64_t ts) {
return ts > (RELATIVE_TS_BASE - (1LL<<48));
}
/**
* Wrap a given time stamp, if there is an indication for an overflow
*
* @param st stream
* @param timestamp the time stamp to wrap
* @return resulting time stamp
*/
static int64_t wrap_timestamp(const AVStream *st, int64_t timestamp)
if (st->pts_wrap_behavior != AV_PTS_WRAP_IGNORE &&
st->pts_wrap_reference != AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) {
if (st->pts_wrap_behavior == AV_PTS_WRAP_ADD_OFFSET &&
timestamp < st->pts_wrap_reference)
return timestamp + (1ULL << st->pts_wrap_bits);
else if (st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET &&
timestamp >= st->pts_wrap_reference)
return timestamp - (1ULL << st->pts_wrap_bits);
}
return timestamp;
}
James Almer
committed
#if FF_API_FORMAT_GET_SET
MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate)
#if FF_API_LAVF_FFSERVER
FF_DISABLE_DEPRECATION_WARNINGS
MAKE_ACCESSORS(AVStream, stream, char *, recommended_encoder_configuration)
FF_ENABLE_DEPRECATION_WARNINGS
#endif
MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, video_codec)
MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, audio_codec)
MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, subtitle_codec)
MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, data_codec)
MAKE_ACCESSORS(AVFormatContext, format, int, metadata_header_padding)
MAKE_ACCESSORS(AVFormatContext, format, void *, opaque)
MAKE_ACCESSORS(AVFormatContext, format, av_format_control_message, control_message_cb)
#if FF_API_OLD_OPEN_CALLBACKS
FF_DISABLE_DEPRECATION_WARNINGS
MAKE_ACCESSORS(AVFormatContext, format, AVOpenCallback, open_cb)
FF_ENABLE_DEPRECATION_WARNINGS
#endif
James Almer
committed
#endif
int64_t av_stream_get_end_pts(const AVStream *st)
{
if (st->internal->priv_pts) {
return st->internal->priv_pts->val;
} else
return AV_NOPTS_VALUE;
struct AVCodecParserContext *av_stream_get_parser(const AVStream *st)
{
return st->parser;
}
Michael Niedermayer
committed
void av_format_inject_global_side_data(AVFormatContext *s)
{
int i;
s->internal->inject_global_side_data = 1;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
st->inject_global_side_data = 1;
}
}
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
av_assert0(!dst->codec_whitelist &&
!dst->format_whitelist &&
!dst->protocol_whitelist &&
!dst->protocol_blacklist);
dst-> codec_whitelist = av_strdup(src->codec_whitelist);
dst->format_whitelist = av_strdup(src->format_whitelist);
dst->protocol_whitelist = av_strdup(src->protocol_whitelist);
dst->protocol_blacklist = av_strdup(src->protocol_blacklist);
if ( (src-> codec_whitelist && !dst-> codec_whitelist)
|| (src-> format_whitelist && !dst-> format_whitelist)
|| (src->protocol_whitelist && !dst->protocol_whitelist)
|| (src->protocol_blacklist && !dst->protocol_blacklist)) {
av_log(dst, AV_LOG_ERROR, "Failed to duplicate black/whitelist\n");
return AVERROR(ENOMEM);
}
return 0;
}
static const AVCodec *find_decoder(AVFormatContext *s, const AVStream *st, enum AVCodecID codec_id)
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS
if (st->codec->codec)
return st->codec->codec;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
switch (st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO:
if (s->video_codec) return s->video_codec;
break;
case AVMEDIA_TYPE_AUDIO:
if (s->audio_codec) return s->audio_codec;
break;
case AVMEDIA_TYPE_SUBTITLE:
if (s->subtitle_codec) return s->subtitle_codec;
return avcodec_find_decoder(codec_id);
}
static const AVCodec *find_probe_decoder(AVFormatContext *s, const AVStream *st, enum AVCodecID codec_id)
{
const AVCodec *codec;
#if CONFIG_H264_DECODER
/* Other parts of the code assume this decoder to be used for h264,
* so force it if possible. */
if (codec_id == AV_CODEC_ID_H264)
return avcodec_find_decoder_by_name("h264");
#endif
codec = find_decoder(s, st, codec_id);
if (!codec)
return NULL;
if (codec->capabilities & AV_CODEC_CAP_AVOID_PROBING) {
const AVCodec *probe_codec = NULL;
while (probe_codec = av_codec_next(probe_codec)) {
if (probe_codec->id == codec_id &&
av_codec_is_decoder(probe_codec) &&
!(probe_codec->capabilities & (AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_EXPERIMENTAL))) {
return probe_codec;
}
}
}
return codec;
James Almer
committed
#if FF_API_FORMAT_GET_SET
int av_format_get_probe_score(const AVFormatContext *s)
{
return s->probe_score;
}
James Almer
committed
#endif
/* an arbitrarily chosen "sane" max packet size -- 50M */
#define SANE_CHUNK_SIZE (50000000)
int ffio_limit(AVIOContext *s, int size)
if (s->maxsize>= 0) {
int64_t remaining= s->maxsize - avio_tell(s);
if (remaining < size) {
int64_t newsize = avio_size(s);
if (!s->maxsize || s->maxsize<newsize)
s->maxsize = newsize - !newsize;
remaining= s->maxsize - avio_tell(s);
Michael Niedermayer
committed
remaining= FFMAX(remaining, 0);
if (s->maxsize>= 0 && remaining+1 < size) {
av_log(NULL, remaining ? AV_LOG_ERROR : AV_LOG_DEBUG, "Truncating packet of size %d to %"PRId64"\n", size, remaining+1);
size = remaining+1;
}
/* Read the data in sane-sized chunks and append to pkt.
* Return the number of bytes read or an error. */
static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size)
int64_t orig_pos = pkt->pos; // av_grow_packet might reset pos
int orig_size = pkt->size;
do {
int prev_size = pkt->size;
int read_size;
/* When the caller requests a lot of data, limit it to the amount
* left in file or SANE_CHUNK_SIZE when it is not known. */
read_size = size;
if (read_size > SANE_CHUNK_SIZE/10) {
read_size = ffio_limit(s, read_size);
// If filesize/maxsize is unknown, limit to SANE_CHUNK_SIZE
if (s->maxsize < 0)
read_size = FFMIN(read_size, SANE_CHUNK_SIZE);
}
ret = av_grow_packet(pkt, read_size);
if (ret < 0)
break;
ret = avio_read(s, pkt->data + prev_size, read_size);
if (ret != read_size) {
av_shrink_packet(pkt, prev_size + FFMAX(ret, 0));
break;
}
size -= read_size;
} while (size > 0);
if (size > 0)
pkt->flags |= AV_PKT_FLAG_CORRUPT;
pkt->pos = orig_pos;
if (!pkt->size)
av_packet_unref(pkt);
return pkt->size > orig_size ? pkt->size - orig_size : ret;
}
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
{
av_init_packet(pkt);
pkt->data = NULL;
pkt->size = 0;
pkt->pos = avio_tell(s);
return append_packet_chunked(s, pkt, size);
int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
{
if (!pkt->size)
return av_get_packet(s, pkt, size);
return append_packet_chunked(s, pkt, size);
}
Michel Bardiaux
committed
int av_filename_number_test(const char *filename)
Fabrice Bellard
committed
{
char buf[1024];
return filename &&
(av_get_frame_filename(buf, sizeof(buf), filename, 1) >= 0);
Fabrice Bellard
committed
}
static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st,
AVProbeData *pd)
Michael Niedermayer
committed
{
static const struct {
const char *name;
enum AVCodecID id;
enum AVMediaType type;
} fmt_id_type[] = {
{ "aac", AV_CODEC_ID_AAC, AVMEDIA_TYPE_AUDIO },
{ "ac3", AV_CODEC_ID_AC3, AVMEDIA_TYPE_AUDIO },
{ "aptx", AV_CODEC_ID_APTX, AVMEDIA_TYPE_AUDIO },
{ "dts", AV_CODEC_ID_DTS, AVMEDIA_TYPE_AUDIO },
{ "dvbsub", AV_CODEC_ID_DVB_SUBTITLE,AVMEDIA_TYPE_SUBTITLE },
{ "dvbtxt", AV_CODEC_ID_DVB_TELETEXT,AVMEDIA_TYPE_SUBTITLE },
{ "eac3", AV_CODEC_ID_EAC3, AVMEDIA_TYPE_AUDIO },
{ "h264", AV_CODEC_ID_H264, AVMEDIA_TYPE_VIDEO },
{ "hevc", AV_CODEC_ID_HEVC, AVMEDIA_TYPE_VIDEO },
{ "loas", AV_CODEC_ID_AAC_LATM, AVMEDIA_TYPE_AUDIO },
{ "m4v", AV_CODEC_ID_MPEG4, AVMEDIA_TYPE_VIDEO },
{ "mjpeg_2000",AV_CODEC_ID_JPEG2000, AVMEDIA_TYPE_VIDEO },
{ "mp3", AV_CODEC_ID_MP3, AVMEDIA_TYPE_AUDIO },
{ "mpegvideo", AV_CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO },
{ "truehd", AV_CODEC_ID_TRUEHD, AVMEDIA_TYPE_AUDIO },
{ 0 }
};
int score;
AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score);
Michael Niedermayer
committed
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)) {
if (fmt_id_type[i].type != AVMEDIA_TYPE_AUDIO &&
st->codecpar->sample_rate)
continue;
Michael Niedermayer
committed
if (st->request_probe > score &&
st->codecpar->codec_id != fmt_id_type[i].id)
continue;
st->codecpar->codec_id = fmt_id_type[i].id;
st->codecpar->codec_type = fmt_id_type[i].type;
st->internal->need_context_update = 1;
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS
st->codec->codec_type = st->codecpar->codec_type;
st->codec->codec_id = st->codecpar->codec_id;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
Carl Eugen Hoyos
committed
return score;
Michael Niedermayer
committed
}
Carl Eugen Hoyos
committed
return 0;
Michael Niedermayer
committed
}
Fabrice Bellard
committed
/************************************************************/
/* input media file */
int av_demuxer_open(AVFormatContext *ic) {
if (ic->format_whitelist && av_match_list(ic->iformat->name, ic->format_whitelist, ',') <= 0) {
av_log(ic, AV_LOG_ERROR, "Format not on whitelist \'%s\'\n", ic->format_whitelist);
if (ic->iformat->read_header) {
err = ic->iformat->read_header(ic);
if (err < 0)
return err;
}
if (ic->pb && !ic->internal->data_offset)
ic->internal->data_offset = avio_tell(ic->pb);
/* Open input file and probe the format if necessary. */
static int init_input(AVFormatContext *s, const char *filename,
AVDictionary **options)
{
int ret;
AVProbeData pd = { filename, NULL, 0 };
Michael Niedermayer
committed
int score = AVPROBE_SCORE_RETRY;
if (s->pb) {
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if (!s->iformat)
return av_probe_input_buffer2(s->pb, &s->iformat, filename,
Michael Niedermayer
committed
s, 0, s->format_probesize);
else if (s->iformat->flags & AVFMT_NOFILE)
av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
"will be ignored with AVFMT_NOFILE format.\n");
return 0;
if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
Michael Niedermayer
committed
(!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
if (s->iformat)
return 0;
return av_probe_input_buffer2(s->pb, &s->iformat, filename,
Michael Niedermayer
committed
s, 0, s->format_probesize);
}
int ff_packet_list_put(AVPacketList **packet_buffer,
AVPacketList **plast_pktl,
AVPacket *pkt, int flags)
AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
if (flags & FF_PACKETLIST_FLAG_REF_PACKET) {
if ((ret = av_packet_ref(&pktl->pkt, pkt)) < 0) {
av_free(pktl);
return ret;
}
} else {
// TODO: Adapt callers in this file so the line below can use
// av_packet_move_ref() to effectively move the reference
// to the list.
if (*packet_buffer)
(*plast_pktl)->next = pktl;
else
*packet_buffer = pktl;
/* Add the packet in the buffered packet list. */
int avformat_queue_attached_pictures(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++)
if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC &&
s->streams[i]->discard < AVDISCARD_ALL) {
if (s->streams[i]->attached_pic.size <= 0) {
av_log(s, AV_LOG_WARNING,
"Attached picture on stream %d has invalid size, "
"ignoring\n", i);
continue;
}
ret = ff_packet_list_put(&s->internal->raw_packet_buffer,
&s->internal->raw_packet_buffer_end,
&s->streams[i]->attached_pic,
FF_PACKETLIST_FLAG_REF_PACKET);
static int update_stream_avctx(AVFormatContext *s)
{
int i, ret;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
if (!st->internal->need_context_update)
/* close parser, because it depends on the codec */
if (st->parser && st->internal->avctx->codec_id != st->codecpar->codec_id) {
av_parser_close(st->parser);
st->parser = NULL;
}
/* update internal codec context, for the parser */
ret = avcodec_parameters_to_context(st->internal->avctx, st->codecpar);
if (ret < 0)
return ret;
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS
/* update deprecated public codec context */
ret = avcodec_parameters_to_context(st->codec, st->codecpar);
if (ret < 0)
return ret;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
st->internal->need_context_update = 0;
}
return 0;
}
int avformat_open_input(AVFormatContext **ps, const char *filename,
AVInputFormat *fmt, AVDictionary **options)
{
AVFormatContext *s = *ps;
AVDictionary *tmp = NULL;
ID3v2ExtraMeta *id3v2_extra_meta = NULL;
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
if (!s->av_class) {
av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");
return AVERROR(EINVAL);
}
if (fmt)
s->iformat = fmt;
if (options)
av_dict_copy(&tmp, *options, 0);
if (s->pb) // must be before any goto fail
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if ((ret = av_opt_set_dict(s, &tmp)) < 0)
goto fail;
if (!(s->url = av_strdup(filename ? filename : ""))) {
ret = AVERROR(ENOMEM);
goto fail;
}
#if FF_API_FORMAT_FILENAME
FF_DISABLE_DEPRECATION_WARNINGS
av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename));
FF_ENABLE_DEPRECATION_WARNINGS
#endif
if ((ret = init_input(s, filename, &tmp)) < 0)
goto fail;
if (!s->protocol_whitelist && s->pb && s->pb->protocol_whitelist) {
s->protocol_whitelist = av_strdup(s->pb->protocol_whitelist);
if (!s->protocol_whitelist) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
if (!s->protocol_blacklist && s->pb && s->pb->protocol_blacklist) {
s->protocol_blacklist = av_strdup(s->pb->protocol_blacklist);
if (!s->protocol_blacklist) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
if (s->format_whitelist && av_match_list(s->iformat->name, s->format_whitelist, ',') <= 0) {
av_log(s, AV_LOG_ERROR, "Format not on whitelist \'%s\'\n", s->format_whitelist);
ret = AVERROR(EINVAL);
goto fail;
}
avio_skip(s->pb, s->skip_initial_bytes);
/* Check filename in case an image number is expected. */
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
if (!av_filename_number_test(filename)) {
ret = AVERROR(EINVAL);
Fabrice Bellard
committed
}
}
s->duration = s->start_time = AV_NOPTS_VALUE;
if (s->iformat->priv_data_size > 0) {
if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
ret = AVERROR(ENOMEM);
goto fail;
Fabrice Bellard
committed
}
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;
}
Fabrice Bellard
committed
}
/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
if (s->pb)
ff_id3v2_read_dict(s->pb, &s->internal->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
if ((ret = s->iformat->read_header(s)) < 0)
goto fail;
if (!s->metadata) {
s->metadata = s->internal->id3v2_meta;
s->internal->id3v2_meta = NULL;
} else if (s->internal->id3v2_meta) {
int level = AV_LOG_WARNING;
if (s->error_recognition & AV_EF_COMPLIANT)
level = AV_LOG_ERROR;
av_log(s, level, "Discarding ID3 tags because more suitable tags were found.\n");
av_dict_free(&s->internal->id3v2_meta);
if (s->error_recognition & AV_EF_EXPLODE)
return AVERROR_INVALIDDATA;
}
if (id3v2_extra_meta) {
if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") ||
!strcmp(s->iformat->name, "tta")) {
if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
goto fail;
if ((ret = ff_id3v2_parse_chapters(s, &id3v2_extra_meta)) < 0)
goto fail;
if ((ret = ff_id3v2_parse_priv(s, &id3v2_extra_meta)) < 0)
goto fail;
} else
av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n");
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
if ((ret = avformat_queue_attached_pictures(s)) < 0)
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->internal->data_offset)
s->internal->data_offset = avio_tell(s->pb);
s->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
update_stream_avctx(s);
for (i = 0; i < s->nb_streams; i++)
s->streams[i]->internal->orig_codec_id = s->streams[i]->codecpar->codec_id;
if (options) {
av_dict_free(options);
*options = tmp;
*ps = s;
Fabrice Bellard
committed
return 0;
fail:
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
av_dict_free(&tmp);
if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
Michael Niedermayer
committed
avio_closep(&s->pb);
avformat_free_context(s);
*ps = NULL;
return ret;
/*******************************************************/
static void force_codec_ids(AVFormatContext *s, AVStream *st)
{
switch (st->codecpar->codec_type) {
if (s->video_codec_id)
st->codecpar->codec_id = s->video_codec_id;
break;
case AVMEDIA_TYPE_AUDIO:
if (s->audio_codec_id)
st->codecpar->codec_id = s->audio_codec_id;
break;
case AVMEDIA_TYPE_SUBTITLE:
if (s->subtitle_codec_id)
st->codecpar->codec_id = s->subtitle_codec_id;
case AVMEDIA_TYPE_DATA:
if (s->data_codec_id)
st->codecpar->codec_id = s->data_codec_id;
break;
static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
if (st->request_probe>0) {
int end;
av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets);
if (pkt) {
uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
if (!new_buf) {
av_log(s, AV_LOG_WARNING,
"Failed to reallocate probe buffer for stream %d\n",
st->index);
}
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);
} else {
st->probe_packets = 0;
if (!pd->buf_size) {
av_log(s, AV_LOG_WARNING,
"nothing to probe for stream %d\n", st->index);
end= s->internal->raw_packet_buffer_remaining_size <= 0
|| st->probe_packets<= 0;
if (end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)) {
int score = set_codec_from_probe_data(s, st, pd);
if ( (st->codecpar->codec_id != AV_CODEC_ID_NONE && score > AVPROBE_SCORE_STREAM_RETRY)
st->request_probe = -1;
if (st->codecpar->codec_id != AV_CODEC_ID_NONE) {
av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index);
force_codec_ids(s, st);
static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index, AVPacket *pkt)
{
int64_t ref = pkt->dts;
int i, pts_wrap_behavior;
int64_t pts_wrap_reference;
AVProgram *first_program;
if (ref == AV_NOPTS_VALUE)
ref = pkt->pts;
if (st->pts_wrap_reference != AV_NOPTS_VALUE || st->pts_wrap_bits >= 63 || ref == AV_NOPTS_VALUE || !s->correct_ts_overflow)
return 0;
ref &= (1LL << st->pts_wrap_bits)-1;
// reference time stamp should be 60 s before first time stamp
pts_wrap_reference = ref - av_rescale(60, st->time_base.den, st->time_base.num);
// if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset
pts_wrap_behavior = (ref < (1LL << st->pts_wrap_bits) - (1LL << st->pts_wrap_bits-3)) ||
(ref < (1LL << st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ?
AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET;
first_program = av_find_program_from_stream(s, NULL, stream_index);
if (!first_program) {
int default_stream_index = av_find_default_stream_index(s);
if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) {
for (i = 0; i < s->nb_streams; i++) {
Michael Niedermayer
committed
if (av_find_program_from_stream(s, NULL, i))
continue;
s->streams[i]->pts_wrap_reference = pts_wrap_reference;
s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
}
}
else {
st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
}
}
else {
AVProgram *program = first_program;
while (program) {
if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
pts_wrap_reference = program->pts_wrap_reference;
pts_wrap_behavior = program->pts_wrap_behavior;
break;
}
program = av_find_program_from_stream(s, program, stream_index);
}
// update every program with differing pts_wrap_reference
program = first_program;
while (program) {
if (program->pts_wrap_reference != pts_wrap_reference) {
for (i = 0; i<program->nb_stream_indexes; i++) {
s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference;
s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior;
}
program->pts_wrap_reference = pts_wrap_reference;
program->pts_wrap_behavior = pts_wrap_behavior;
}
program = av_find_program_from_stream(s, program, stream_index);
}
}
return 1;
}
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
AVPacketList *pktl = s->internal->raw_packet_buffer;
if (pktl) {
*pkt = pktl->pkt;
st = s->streams[pkt->stream_index];
if (s->internal->raw_packet_buffer_remaining_size <= 0)
if ((err = probe_codec(s, st, NULL)) < 0)
return err;
if (st->request_probe <= 0) {
s->internal->raw_packet_buffer = pktl->next;
s->internal->raw_packet_buffer_remaining_size += pkt->size;
av_free(pktl);
return 0;
}
}
pkt->data = NULL;
pkt->size = 0;
ret = s->iformat->read_packet(s, pkt);
if (ret < 0) {
/* Some demuxers return FFERROR_REDO when they consume
data and discard it (ignored streams, junk, extradata).
We must re-call the demuxer to get the real packet. */
if (ret == FFERROR_REDO)
continue;
if (!pktl || ret == AVERROR(EAGAIN))
return ret;
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
if (st->probe_packets || st->request_probe > 0)
if ((err = probe_codec(s, st, NULL)) < 0)
return err;
av_assert0(st->request_probe <= 0);
continue;
}
James Almer
committed
err = av_packet_make_refcounted(pkt);
if (err < 0)
return err;
if ((s->flags & AVFMT_FLAG_DISCARD_CORRUPT) &&
(pkt->flags & AV_PKT_FLAG_CORRUPT)) {
av_log(s, AV_LOG_WARNING,
"Dropped corrupted packet (stream = %d)\n",
pkt->stream_index);
av_packet_unref(pkt);
if (pkt->stream_index >= (unsigned)s->nb_streams) {
av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index);
continue;
}
st = s->streams[pkt->stream_index];
if (update_wrap_reference(s, st, pkt->stream_index, pkt) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
// correct first time stamps to negative values
if (!is_relative(st->first_dts))
st->first_dts = wrap_timestamp(st, st->first_dts);
if (!is_relative(st->start_time))
st->start_time = wrap_timestamp(st, st->start_time);
if (!is_relative(st->cur_dts))
st->cur_dts = wrap_timestamp(st, st->cur_dts);
}
pkt->dts = wrap_timestamp(st, pkt->dts);
pkt->pts = wrap_timestamp(st, pkt->pts);
/* TODO: audio: time filter; video: frame reordering (pts != dts) */
if (s->use_wallclock_as_timestamps)
pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
if (!pktl && st->request_probe <= 0)
return ret;
err = ff_packet_list_put(&s->internal->raw_packet_buffer,
&s->internal->raw_packet_buffer_end,
pkt, 0);
s->internal->raw_packet_buffer_remaining_size -= pkt->size;
if ((err = probe_codec(s, st, pkt)) < 0)
return err;
/**********************************************************/
static int determinable_frame_size(AVCodecContext *avctx)
{
Michael Niedermayer
committed
switch(avctx->codec_id) {
case AV_CODEC_ID_MP1:
case AV_CODEC_ID_MP2:
case AV_CODEC_ID_MP3:
Michael Niedermayer
committed
}
Daniel Kristjansson
committed
/**
* Return the frame duration in seconds. Return 0 if not available.
Daniel Kristjansson
committed
*/
void ff_compute_frame_duration(AVFormatContext *s, int *pnum, int *pden, AVStream *st,
AVCodecParserContext *pc, AVPacket *pkt)
AVRational codec_framerate = s->iformat ? st->internal->avctx->framerate :
av_mul_q(av_inv_q(st->internal->avctx->time_base), (AVRational){1, st->internal->avctx->ticks_per_frame});
int frame_size, sample_rate;
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS
if ((!codec_framerate.den || !codec_framerate.num) && st->codec->time_base.den && st->codec->time_base.num)
codec_framerate = av_mul_q(av_inv_q(st->codec->time_base), (AVRational){1, st->codec->ticks_per_frame});
FF_ENABLE_DEPRECATION_WARNINGS
#endif
*pnum = 0;
*pden = 0;
switch (st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO:
Michael Niedermayer
committed
if (st->r_frame_rate.num && !pc && s->iformat) {
*pnum = st->r_frame_rate.den;
*pden = st->r_frame_rate.num;
} else if (st->time_base.num * 1000LL > st->time_base.den) {
*pnum = st->time_base.num;
*pden = st->time_base.den;
} else if (codec_framerate.den * 1000LL > codec_framerate.num) {
av_assert0(st->internal->avctx->ticks_per_frame);
Michael Niedermayer
committed
av_reduce(pnum, pden,
codec_framerate.den,
codec_framerate.num * (int64_t)st->internal->avctx->ticks_per_frame,
Michael Niedermayer
committed
INT_MAX);
if (pc && pc->repeat_pict) {
av_assert0(s->iformat); // this may be wrong for interlaced encoding but its not used for that case
Michael Niedermayer
committed
av_reduce(pnum, pden,
(*pnum) * (1LL + pc->repeat_pict),
(*pden),
INT_MAX);
/* 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->internal->avctx->ticks_per_frame > 1 && !pc)
Michael Niedermayer
committed
*pnum = *pden = 0;
case AVMEDIA_TYPE_AUDIO:
if (st->internal->avctx_inited) {
frame_size = av_get_audio_frame_duration(st->internal->avctx, pkt->size);
sample_rate = st->internal->avctx->sample_rate;
} else {
frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size);
sample_rate = st->codecpar->sample_rate;
}