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
#undef NDEBUG
#include <assert.h>
#include <stdarg.h>
#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 "libavcodec/bytestream.h"
#include "libavcodec/internal.h"
#include "avformat.h"
#include "id3v2.h"
#include "internal.h"
#include "metadata.h"
#if CONFIG_NETWORK
#include "network.h"
#endif
#include "riff.h"
#include "url.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;
/* an arbitrarily chosen "sane" max packet size -- 50M */
#define SANE_CHUNK_SIZE (50000000)
/* 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 chunk_size = size;
int64_t orig_pos = pkt->pos; // av_grow_packet might reset pos
int orig_size = pkt->size;
int ret = 0;
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. */
if (size > SANE_CHUNK_SIZE) {
int64_t filesize = avio_size(s) - avio_tell(s);
chunk_size = FFMAX(filesize, SANE_CHUNK_SIZE);
}
read_size = FFMIN(size, 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);
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, int score)
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 },
{ "dts", AV_CODEC_ID_DTS, AVMEDIA_TYPE_AUDIO },
{ "eac3", AV_CODEC_ID_EAC3, AVMEDIA_TYPE_AUDIO },
{ "h264", AV_CODEC_ID_H264, AVMEDIA_TYPE_VIDEO },
{ "latm", AV_CODEC_ID_AAC_LATM, AVMEDIA_TYPE_AUDIO },
{ "m4v", AV_CODEC_ID_MPEG4, AVMEDIA_TYPE_VIDEO },
{ "mp3", AV_CODEC_ID_MP3, AVMEDIA_TYPE_AUDIO },
{ "mpegvideo", AV_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->codecpar->codec_id = fmt_id_type[i].id;
st->codecpar->codec_type = fmt_id_type[i].type;
#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
break;
}
Michael Niedermayer
committed
}
return !!fmt;
}
Fabrice Bellard
committed
/************************************************************/
/* input media file */
/* 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 };
if (s->pb) {
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if (!s->iformat)
return av_probe_input_buffer(s->pb, &s->iformat, filename,
s, 0, s->probesize);
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;
ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ, options);
if (ret < 0)
if (s->iformat)
return 0;
return av_probe_input_buffer(s->pb, &s->iformat, filename,
s, 0, s->probesize);
}
static int add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
AVPacketList **plast_pktl, int ref)
AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
return AVERROR(ENOMEM);
if (ref) {
if ((ret = av_packet_ref(&pktl->pkt, pkt)) < 0) {
av_free(pktl);
return ret;
}
} else {
pktl->pkt = *pkt;
}
if (*packet_buffer)
(*plast_pktl)->next = pktl;
else
*packet_buffer = pktl;
/* Add the packet in the buffered packet list. */
static int 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) {
ret = add_to_pktbuf(&s->internal->raw_packet_buffer,
&s->streams[i]->attached_pic,
&s->internal->raw_packet_buffer_end, 1);
if (ret < 0)
return ret;
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS
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_codec_update)
continue;
ret = avcodec_parameters_to_context(st->codec, st->codecpar);
if (ret < 0)
return ret;
st->internal->need_codec_update = 0;
}
return 0;
}
FF_ENABLE_DEPRECATION_WARNINGS
#endif
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 (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, &tmp)) < 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;
Anton Khirnov
committed
av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename));
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, &id3v2_extra_meta);
if (s->iformat->read_header)
if ((ret = s->iformat->read_header(s)) < 0)
goto fail;
if (id3v2_extra_meta &&
(ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
goto fail;
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
if ((ret = queue_attached_pictures(s)) < 0)
goto fail;
if (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;
#if FF_API_LAVF_AVCTX
update_stream_avctx(s);
#endif
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;
return 0;
fail:
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
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 int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
if (st->codecpar->codec_id == AV_CODEC_ID_PROBE) {
AVProbeData *pd = &st->probe_data;
av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index);
--st->probe_packets;
if (pkt) {
int err;
if ((err = av_reallocp(&pd->buf, pd->buf_size + pkt->size +
AVPROBE_PADDING_SIZE)) < 0)
return err;
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_ERROR,
"nothing to probe for stream %d\n", st->index);
if (!st->probe_packets ||
av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)) {
set_codec_from_probe_data(s, st, pd, st->probe_packets > 0
? AVPROBE_SCORE_MAX / 4 : 0);
if (st->codecpar->codec_id != AV_CODEC_ID_PROBE) {
av_freep(&pd->buf);
av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
}
}
}
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 (st->codecpar->codec_id != AV_CODEC_ID_PROBE ||
s->internal->raw_packet_buffer_remaining_size < pkt->size) {
AVProbeData *pd;
if ((err = probe_codec(s, st, NULL)) < 0)
return err;
pd = &st->probe_data;
av_freep(&pd->buf);
pd->buf_size = 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) {
if (!pktl || ret == AVERROR(EAGAIN))
return ret;
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
if ((err = probe_codec(s, st, NULL)) < 0)
return err;
continue;
}
if (!pkt->buf) {
AVPacket tmp = { 0 };
ret = av_packet_ref(&tmp, pkt);
if (ret < 0)
return ret;
*pkt = tmp;
}
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);
st = s->streams[pkt->stream_index];
switch (st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO:
st->codecpar->codec_id = s->video_codec_id;
case AVMEDIA_TYPE_AUDIO:
st->codecpar->codec_id = s->audio_codec_id;
case AVMEDIA_TYPE_SUBTITLE:
st->codecpar->codec_id = s->subtitle_codec_id;
if (!pktl && (st->codecpar->codec_id != AV_CODEC_ID_PROBE ||
return ret;
err = add_to_pktbuf(&s->internal->raw_packet_buffer, pkt,
&s->internal->raw_packet_buffer_end, 0);
if (err)
return err;
s->internal->raw_packet_buffer_remaining_size -= pkt->size;
if ((err = probe_codec(s, st, pkt)) < 0)
return err;
}
/**********************************************************/
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 :
(AVRational){ 0, 1 };
int frame_size;
*pnum = 0;
*pden = 0;
switch (st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO:
if (st->avg_frame_rate.num) {
*pnum = st->avg_frame_rate.den;
*pden = st->avg_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) {
*pnum = codec_framerate.den;
*pden = codec_framerate.num;
if (pc && pc->repeat_pict) {
if (*pnum > INT_MAX / (1 + pc->repeat_pict))
*pden /= 1 + pc->repeat_pict;
else
*pnum *= 1 + pc->repeat_pict;
/* 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:
frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size);
if (frame_size <= 0 || st->codecpar->sample_rate <= 0)
break;
*pnum = frame_size;
*pden = st->codecpar->sample_rate;
break;
default:
break;
}
}
static int is_intra_only(enum AVCodecID id)
{
const AVCodecDescriptor *d = avcodec_descriptor_get(id);
if (!d)
return 0;
if (d->type == AVMEDIA_TYPE_VIDEO && !(d->props & AV_CODEC_PROP_INTRA_ONLY))
return 0;
return 1;
Michael Niedermayer
committed
}
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->internal->packet_buffer;
if (st->first_dts != AV_NOPTS_VALUE ||
dts == AV_NOPTS_VALUE ||
st->cur_dts == AV_NOPTS_VALUE)
st->first_dts = dts - st->cur_dts;
st->cur_dts = dts;
for (; pktl; pktl = pktl->next) {
if (pktl->pkt.stream_index != stream_index)
// 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;
static void update_initial_durations(AVFormatContext *s, AVStream *st,
int stream_index, int duration)
Michael Niedermayer
committed
{
AVPacketList *pktl = s->internal->packet_buffer;
if (st->first_dts != AV_NOPTS_VALUE) {
cur_dts = st->first_dts;
for (; pktl; pktl = pktl->next) {
if (pktl->pkt.stream_index == stream_index) {
if (pktl->pkt.pts != pktl->pkt.dts ||
pktl->pkt.dts != AV_NOPTS_VALUE ||
pktl->pkt.duration)
break;
cur_dts -= duration;
}
}
pktl = s->internal->packet_buffer;
st->first_dts = cur_dts;
return;
Michael Niedermayer
committed
for (; pktl; pktl = pktl->next) {
if (pktl->pkt.stream_index != stream_index)
Michael Niedermayer
committed
continue;
if (pktl->pkt.pts == pktl->pkt.dts &&
pktl->pkt.dts == AV_NOPTS_VALUE &&
!pktl->pkt.duration) {
pktl->pkt.dts = cur_dts;
if (!st->internal->avctx->has_b_frames)
cur_dts += duration;
if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
pktl->pkt.duration = duration;
Michael Niedermayer
committed
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;
/* do we have a video B-frame ? */
delay = st->internal->avctx->has_b_frames;
presentation_delayed = 0;
/* XXX: need has_b_frame, but cannot get it if the codec is
if (delay &&
pc && pc->pict_type != AV_PICTURE_TYPE_B)
presentation_delayed = 1;
if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE &&
st->pts_wrap_bits < 63 &&
pkt->dts - (1LL << (st->pts_wrap_bits - 1)) > pkt->pts) {
pkt->dts -= 1LL << st->pts_wrap_bits;
Michael Niedermayer
committed
}
/* Some MPEG-2 in MPEG-PS lack dts (issue #171 / input_file.mpg).
* We take the conservative approach and discard both.
* Note: If this is misbehaving for an 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");
pkt->dts = AV_NOPTS_VALUE;
Michael Niedermayer
committed
}
if (pkt->duration == 0 && st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {
ff_compute_frame_duration(s, &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->internal->packet_buffer)
update_initial_durations(s, st, pkt->stream_index,
pkt->duration);
/* 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)
if (pkt->dts != AV_NOPTS_VALUE)
pkt->dts += offset;
}
/* This may be redundant, but it should not hurt. */
if (pkt->dts != AV_NOPTS_VALUE &&
pkt->pts != AV_NOPTS_VALUE &&
pkt->pts > pkt->dts)
av_log(NULL, AV_LOG_TRACE,
"IN delayed:%d pts:%"PRId64", dts:%"PRId64" "
"cur_dts:%"PRId64" st:%d pc:%p\n",
presentation_delayed, pkt->pts, pkt->dts, st->cur_dts,
pkt->stream_index, pc);
/* Interpolate PTS and DTS if they are not present. We skip H.264
* currently because delay and has_b_frames are not reliably set. */
if ((delay == 0 || (delay == 1 && pc)) &&
st->codecpar->codec_id != AV_CODEC_ID_H264) {
/* DTS = decompression timestamp */
/* PTS = presentation timestamp */
update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts);
if (pkt->dts == AV_NOPTS_VALUE)
pkt->dts = st->cur_dts;
/* This is tricky: the dts must be incremented by the duration
* of the frame we are displaying, i.e. the last I- or P-frame. */
if (st->last_IP_duration == 0)
st->last_IP_duration = pkt->duration;
if (pkt->dts != AV_NOPTS_VALUE)
st->last_IP_duration = pkt->duration;
st->last_IP_pts = pkt->pts;
/* Cannot compute PTS if not present (we can compute it only
* by knowing the future. */
} else if (pkt->pts != AV_NOPTS_VALUE ||
pkt->dts != AV_NOPTS_VALUE ||
pkt->duration ||
st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
int duration = pkt->duration;
if (!duration && st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
ff_compute_frame_duration(s, &num, &den, st, pc, pkt);
if (den && num) {
duration = av_rescale_rnd(1,
num * (int64_t) st->time_base.den,
den * (int64_t) st->time_base.num,
AV_ROUND_DOWN);
if (duration != 0 && s->internal->packet_buffer)
update_initial_durations(s, st, pkt->stream_index,
duration);
}
}
if (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE ||
duration) {
/* presentation is not delayed : PTS and DTS are the same */
if (pkt->pts == AV_NOPTS_VALUE)
pkt->pts = pkt->dts;
update_initial_timestamps(s, pkt->stream_index, pkt->pts,
pkt->pts);
if (pkt->pts == AV_NOPTS_VALUE)
pkt->pts = st->cur_dts;
pkt->dts = pkt->pts;
if (pkt->pts != AV_NOPTS_VALUE)
st->cur_dts = pkt->pts + duration;
}
if (pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY) {
st->pts_buffer[0] = pkt->pts;
for (i = 0; i<delay && st->pts_buffer[i] > st->pts_buffer[i + 1]; i++)
FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i + 1]);
if (pkt->dts == AV_NOPTS_VALUE)
pkt->dts = st->pts_buffer[0];
// We skipped it above so we try here.
if (st->codecpar->codec_id == AV_CODEC_ID_H264)
// This should happen on the first packet
update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts);
if (pkt->dts > st->cur_dts)
av_log(NULL, AV_LOG_TRACE,
"OUTdelayed:%d/%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64"\n",
presentation_delayed, delay, pkt->pts, pkt->dts, st->cur_dts);
/* update flags */
if (is_intra_only(st->codecpar->codec_id))
pkt->flags |= AV_PKT_FLAG_KEY;
#if FF_API_CONVERGENCE_DURATION
FF_DISABLE_DEPRECATION_WARNINGS
if (pc)
pkt->convergence_duration = pc->convergence_duration;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
static void free_packet_buffer(AVPacketList **pkt_buf, AVPacketList **pkt_buf_end)
{
while (*pkt_buf) {
AVPacketList *pktl = *pkt_buf;
*pkt_buf = pktl->next;
av_packet_unref(&pktl->pkt);
av_freep(&pktl);
}
*pkt_buf_end = NULL;
}
* Parse a packet, add all split parts to parse_queue.
* @param pkt Packet to parse, NULL when flushing the parser at end of stream.
*/
static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
{
AVPacket out_pkt = { 0 }, flush_pkt = { 0 };
AVStream *st = s->streams[stream_index];
uint8_t *data = pkt ? pkt->data : NULL;
int size = pkt ? pkt->size : 0;
int ret = 0, got_output = 0;
if (!pkt) {
av_init_packet(&flush_pkt);
got_output = 1;
}
while (size > 0 || (pkt == &flush_pkt && got_output)) {
int len;
av_init_packet(&out_pkt);
len = av_parser_parse2(st->parser, st->internal->avctx,
&out_pkt.data, &out_pkt.size, data, size,
pkt->pts, pkt->dts, pkt->pos);
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
/* increment read pointer */
data += len;
size -= len;
got_output = !!out_pkt.size;
if (!out_pkt.size)
continue;
if (pkt->side_data) {
out_pkt.side_data = pkt->side_data;
out_pkt.side_data_elems = pkt->side_data_elems;
pkt->side_data = NULL;
pkt->side_data_elems = 0;
/* set the duration */
out_pkt.duration = 0;
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
if (st->internal->avctx->sample_rate > 0) {
out_pkt.duration =
av_rescale_q_rnd(st->parser->duration,
(AVRational) { 1, st->internal->avctx->sample_rate },
st->time_base,
AV_ROUND_DOWN);
}
}
out_pkt.stream_index = st->index;
out_pkt.pts = st->parser->pts;
out_pkt.dts = st->parser->dts;
out_pkt.pos = st->parser->pos;
if (st->parser->key_frame == 1 ||
(st->parser->key_frame == -1 &&
st->parser->pict_type == AV_PICTURE_TYPE_I))
out_pkt.flags |= AV_PKT_FLAG_KEY;
compute_pkt_fields(s, st, st->parser, &out_pkt);
if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
out_pkt.flags & AV_PKT_FLAG_KEY) {
ff_reduce_index(s, st->index);
av_add_index_entry(st, st->parser->frame_offset, out_pkt.dts,
0, 0, AVINDEX_KEYFRAME);
}
if ((ret = add_to_pktbuf(&s->internal->parse_queue, &out_pkt,
&s->internal->parse_queue_end,
1))) {
av_packet_unref(&out_pkt);
goto fail;
}
}
/* end of the stream => close and free the parser */
if (pkt == &flush_pkt) {
av_parser_close(st->parser);
st->parser = NULL;
}
fail:
av_packet_unref(pkt);
static int read_from_packet_buffer(AVPacketList **pkt_buffer,
AVPacketList **pkt_buffer_end,
AVPacket *pkt)
{
AVPacketList *pktl;
av_assert0(*pkt_buffer);
pktl = *pkt_buffer;
*pkt = pktl->pkt;
*pkt_buffer = pktl->next;
if (!pktl->next)
*pkt_buffer_end = NULL;
av_freep(&pktl);
return 0;
}
static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
int ret = 0, i, got_packet = 0;
AVDictionary *metadata = NULL;
while (!got_packet && !s->internal->parse_queue) {
AVStream *st;
AVPacket cur_pkt;
if (ret < 0) {
if (ret == AVERROR(EAGAIN))
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
if (st->parser && st->need_parsing)
parse_packet(s, NULL, st->index);
/* all remaining packets are now in parse_queue =>
* really terminate parsing */
break;
}
ret = 0;
st = s->streams[cur_pkt.stream_index];
if (cur_pkt.pts != AV_NOPTS_VALUE &&
cur_pkt.dts != AV_NOPTS_VALUE &&
cur_pkt.pts < cur_pkt.dts) {
av_log(s, AV_LOG_WARNING,
"Invalid timestamps stream=%d, pts=%"PRId64", "
"dts=%"PRId64", size=%d\n",
cur_pkt.stream_index, cur_pkt.pts,
cur_pkt.dts, cur_pkt.size);
}
if (s->debug & FF_FDEBUG_TS)
av_log(s, AV_LOG_DEBUG,
"ff_read_packet stream=%d, pts=%"PRId64", dts=%"PRId64", "
"size=%d, duration=%"PRId64", flags=%d\n",
cur_pkt.stream_index, cur_pkt.pts, cur_pkt.dts,
cur_pkt.size, cur_pkt.duration, cur_pkt.flags);
if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) {
st->parser = av_parser_init(st->codecpar->codec_id);
/* no parser available: just output the raw packets */
st->need_parsing = AVSTREAM_PARSE_NONE;
else if (st->need_parsing == AVSTREAM_PARSE_HEADERS)
st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
else if (st->need_parsing == AVSTREAM_PARSE_FULL_ONCE)
st->parser->flags |= PARSER_FLAG_ONCE;
}
if (!st->need_parsing || !st->parser) {
/* no parsing needed: we just output the packet as is */
*pkt = cur_pkt;
compute_pkt_fields(s, st, NULL, pkt);
if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
(pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) {
ff_reduce_index(s, st->index);
av_add_index_entry(st, pkt->pos, pkt->dts,
0, 0, AVINDEX_KEYFRAME);
got_packet = 1;
} else if (st->discard < AVDISCARD_ALL) {
if ((ret = parse_packet(s, &cur_pkt, cur_pkt.stream_index)) < 0)
return ret;
} else {
/* free packet */
av_packet_unref(&cur_pkt);
if (!got_packet && s->internal->parse_queue)
ret = read_from_packet_buffer(&s->internal->parse_queue, &s->internal->parse_queue_end, pkt);
av_opt_get_dict_val(s, "metadata", AV_OPT_SEARCH_CHILDREN, &metadata);
if (metadata) {