/*
- * various utility functions for use within Libav
+ * various utility functions for use within FFmpeg
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avio_internal.h"
#include "internal.h"
#include "libavcodec/internal.h"
+#include "libavcodec/raw.h"
#include "libavutil/opt.h"
#include "libavutil/dict.h"
+#include "libavutil/pixdesc.h"
#include "metadata.h"
#include "id3v2.h"
#include "libavutil/avstring.h"
+#include "libavutil/mathematics.h"
#include "riff.h"
#include "audiointerleave.h"
#include "url.h"
/**
* @file
- * various utility functions for use within Libav
+ * various utility functions for use within FFmpeg
*/
unsigned avformat_version(void)
const char *avformat_configuration(void)
{
- return LIBAV_CONFIGURATION;
+ return FFMPEG_CONFIGURATION;
}
const char *avformat_license(void)
{
#define LICENSE_PREFIX "libavformat license: "
- return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
}
/* fraction handling */
* @param num must be >= 0
* @param den must be >= 1
*/
-static void av_frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den)
+static void frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den)
{
num += (den >> 1);
if (num >= den) {
* @param f fractional number
* @param incr increment, can be positive or negative
*/
-static void av_frac_add(AVFrac *f, int64_t incr)
+static void frac_add(AVFrac *f, int64_t incr)
{
int64_t num, den;
return filename && (av_get_frame_filename(buf, sizeof(buf), filename, 1)>=0);
}
-AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max)
+AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret)
{
AVProbeData lpd = *pd;
AVInputFormat *fmt1 = NULL, *fmt;
- int score, id3 = 0;
+ int score, score_max=0;
if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
int id3len = ff_id3v2_tag_len(lpd.buf);
lpd.buf += id3len;
lpd.buf_size -= id3len;
}
- id3 = 1;
}
fmt = NULL;
score = 0;
if (fmt1->read_probe) {
score = fmt1->read_probe(&lpd);
+ if(!score && fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions))
+ score = 1;
} else if (fmt1->extensions) {
if (av_match_ext(lpd.filename, fmt1->extensions)) {
score = 50;
}
}
- if (score > *score_max) {
- *score_max = score;
+ if (score > score_max) {
+ score_max = score;
fmt = fmt1;
- }else if (score == *score_max)
+ }else if (score == score_max)
fmt = NULL;
}
-
- /* 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;
- }
- }
-
+ *score_ret= score_max;
return fmt;
}
+AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max)
+{
+ int score_ret;
+ AVInputFormat *fmt= av_probe_input_format3(pd, is_opened, &score_ret);
+ if(score_ret > *score_max){
+ *score_max= score_ret;
+ return fmt;
+ }else
+ return NULL;
+}
+
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)
+static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd)
{
static const struct {
const char *name; enum CodecID id; enum AVMediaType type;
{ "mpegvideo", CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO },
{ 0 }
};
- AVInputFormat *fmt = av_probe_input_format2(pd, 1, &score);
+ int score;
+ AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score);
if (fmt) {
int i;
}
}
}
- return !!fmt;
+ return score;
}
/************************************************************/
/* 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;
+
+ 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;
+}
+
/**
* Open a media file from an IO stream. 'fmt' must be specified.
*/
AVInputFormat *fmt, AVFormatParameters *ap)
{
int err;
+ AVDictionary *opts;
AVFormatContext *ic;
AVFormatParameters default_ap;
ap=&default_ap;
memset(ap, 0, sizeof(default_ap));
}
+ opts = convert_format_parameters(ap);
if(!ap->prealloced_context)
- ic = avformat_alloc_context();
+ *ic_ptr = ic = avformat_alloc_context();
else
ic = *ic_ptr;
if (!ic) {
err = AVERROR(ENOMEM);
goto fail;
}
- ic->iformat = fmt;
- ic->pb = pb;
- ic->duration = AV_NOPTS_VALUE;
- ic->start_time = AV_NOPTS_VALUE;
- av_strlcpy(ic->filename, filename, sizeof(ic->filename));
+ 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;
- /* allocate private data */
- if (fmt->priv_data_size > 0) {
- ic->priv_data = av_mallocz(fmt->priv_data_size);
- if (!ic->priv_data) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
- if (fmt->priv_class) {
- *(const AVClass**)ic->priv_data = fmt->priv_class;
- av_opt_set_defaults(ic->priv_data);
- }
- } else {
- ic->priv_data = NULL;
- }
+ if ((err = avformat_open_input(&ic, filename, fmt, &opts)) < 0)
+ goto fail;
+ ic->pb = ic->pb ? ic->pb : pb; // don't leak custom pb if it wasn't set above
+
+ *ic_ptr = ic;
+fail:
+ av_dict_free(&opts);
+ return err;
+}
+#endif
- // e.g. AVFMT_NOFILE formats will not have a AVIOContext
- if (ic->pb)
- ff_id3v2_read(ic, ID3v2_DEFAULT_MAGIC);
+int av_demuxer_open(AVFormatContext *ic, AVFormatParameters *ap){
+ int err;
if (ic->iformat->read_header) {
err = ic->iformat->read_header(ic, ap);
if (err < 0)
- goto fail;
+ return err;
}
- if (pb && !ic->data_offset)
+ if (ic->pb && !ic->data_offset)
ic->data_offset = avio_tell(ic->pb);
- ic->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
-
- *ic_ptr = ic;
return 0;
- fail:
- if (ic) {
- int i;
- av_freep(&ic->priv_data);
- for(i=0;i<ic->nb_streams;i++) {
- AVStream *st = ic->streams[i];
- if (st) {
- av_free(st->priv_data);
- av_free(st->codec->extradata);
- av_free(st->codec);
- av_free(st->info);
- }
- av_free(st);
- }
- }
- av_free(ic);
- *ic_ptr = NULL;
- return err;
}
+
/** size of probe buffer, for guessing file type from file contents */
#define PROBE_BUF_MIN 2048
#define PROBE_BUF_MAX (1<<20)
return AVERROR(EINVAL);
}
- for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt && ret >= 0;
+ for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt;
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 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) {
*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);
+ av_log(logctx, AV_LOG_WARNING, "Format %s detected only with low score of %d, misdetection possible!\n", (*fmt)->name, score);
}else
- av_log(logctx, AV_LOG_DEBUG, "Probed with size=%d and score=%d\n", probe_size, score);
+ av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score);
}
}
return ret;
}
+#if FF_API_FORMAT_PARAMETERS
int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
AVInputFormat *fmt,
int buf_size,
AVFormatParameters *ap)
{
int err;
- AVProbeData probe_data, *pd = &probe_data;
- AVIOContext *pb = NULL;
- void *logctx= ap && ap->prealloced_context ? *ic_ptr : NULL;
-
- pd->filename = "";
- if (filename)
- pd->filename = filename;
- pd->buf = NULL;
- pd->buf_size = 0;
-
- if (!fmt) {
- /* guess format if no file can be opened */
- fmt = av_probe_input_format(pd, 0);
- }
+ AVDictionary *opts = convert_format_parameters(ap);
- /* Do not open file if the format does not need it. XXX: specific
- hack needed to handle RTSP/TCP */
- if (!fmt || !(fmt->flags & AVFMT_NOFILE)) {
- /* if no file needed do not try to open one */
- if ((err=avio_open(&pb, filename, AVIO_FLAG_READ)) < 0) {
- goto fail;
- }
- if (buf_size > 0) {
- ffio_set_buf_size(pb, buf_size);
- }
- if (!fmt && (err = av_probe_input_buffer(pb, &fmt, filename, logctx, 0, logctx ? (*ic_ptr)->probesize : 0)) < 0) {
- goto fail;
- }
- }
+ if (!ap || !ap->prealloced_context)
+ *ic_ptr = NULL;
- /* if still no format found, error */
- if (!fmt) {
- err = AVERROR_INVALIDDATA;
- goto fail;
- }
+ err = avformat_open_input(ic_ptr, filename, fmt, &opts);
- /* check filename in case an image number is expected */
- if (fmt->flags & AVFMT_NEEDNUMBER) {
- if (!av_filename_number_test(filename)) {
- err = AVERROR(EINVAL);
- goto fail;
- }
- }
- err = av_open_input_stream(ic_ptr, pb, filename, fmt, ap);
- if (err)
- goto fail;
- return 0;
- fail:
- av_freep(&pd->buf);
- if (pb)
- avio_close(pb);
- if (ap && ap->prealloced_context)
- av_free(*ic_ptr);
- *ic_ptr = NULL;
+ av_dict_free(&opts);
return err;
-
}
+#endif
/* open input file and probe the format if necessary */
static int init_input(AVFormatContext *s, const char *filename)
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);
+ av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
+ "will be ignored with AVFMT_NOFILE format.\n");
return 0;
}
{
AVFormatContext *s = *ps;
int ret = 0;
- AVFormatParameters ap = { 0 };
+ AVFormatParameters ap = { { 0 } };
AVDictionary *tmp = NULL;
if (!s && !(s = avformat_alloc_context()))
if (s->pb)
ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC);
- if (s->iformat->read_header)
+ if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
if ((ret = s->iformat->read_header(s, &ap)) < 0)
goto fail;
- if (s->pb && !s->data_offset)
+ if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
s->data_offset = avio_tell(s->pb);
s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
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;
+ if(s->streams[pkt->stream_index]->request_probe <= 0){
s->raw_packet_buffer = pktl->next;
s->raw_packet_buffer_remaining_size += pkt->size;
av_free(pktl);
if (!pktl || ret == AVERROR(EAGAIN))
return ret;
for (i = 0; i < s->nb_streams; i++)
- s->streams[i]->probe_packets = 0;
+ if(s->streams[i]->request_probe > 0)
+ s->streams[i]->request_probe = -1;
+ continue;
+ }
+
+ 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);
continue;
}
+
+ if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA))
+ av_packet_merge_side_data(pkt);
+
st= s->streams[pkt->stream_index];
switch(st->codec->codec_type){
break;
}
- if(!pktl && (st->codec->codec_id != CODEC_ID_PROBE ||
- !st->probe_packets))
+ if(!pktl && st->request_probe <= 0)
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){
+ if(st->request_probe>0){
AVProbeData *pd = &st->probe_data;
- av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index);
+ int end;
+ av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets);
--st->probe_packets;
pd->buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
pd->buf_size += pkt->size;
memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE);
- if(av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){
- //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){
+ end= s->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->codec->codec_id != CODEC_ID_NONE && score > AVPROBE_SCORE_MAX/4)
+ || end){
pd->buf_size=0;
av_freep(&pd->buf);
+ st->request_probe= -1;
+ if(st->codec->codec_id != CODEC_ID_NONE){
av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
+ }else
+ av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index);
}
}
}
}
-static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt)
+static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
{
AVStream *st;
int len, ret, i;
compute_pkt_fields(s, st, st->parser, pkt);
if((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY){
+ int64_t pos= (st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->pos : st->parser->frame_offset;
ff_reduce_index(s, st->index);
- av_add_index_entry(st, st->parser->frame_offset, pkt->dts,
+ av_add_index_entry(st, pos, pkt->dts,
0, 0, AVINDEX_KEYFRAME);
}
}
}
if(s->debug & FF_FDEBUG_TS)
- av_log(s, AV_LOG_DEBUG, "av_read_frame_internal stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d, duration=%d, flags=%d\n",
+ av_log(s, AV_LOG_DEBUG, "read_frame_internal stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d, duration=%d, flags=%d\n",
pkt->stream_index,
pkt->pts,
pkt->dts,
}
}
if(genpts){
- int ret= av_read_frame_internal(s, pkt);
+ int ret= read_frame_internal(s, pkt);
if(ret<0){
if(pktl && ret != AVERROR(EAGAIN)){
eof=1;
return AVERROR(ENOMEM);
}else{
assert(!s->packet_buffer);
- return av_read_frame_internal(s, pkt);
+ return read_frame_internal(s, pkt);
}
}
}
return pos;
}
-static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags){
+static int seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags){
int64_t pos_min, pos_max;
#if 0
AVStream *st;
return 0;
}
-static int av_seek_frame_generic(AVFormatContext *s,
+static int seek_frame_generic(AVFormatContext *s,
int stream_index, int64_t timestamp, int flags)
{
int index;
ff_read_frame_flush(s);
if(flags & AVSEEK_FLAG_BYTE)
- return av_seek_frame_byte(s, stream_index, timestamp, flags);
+ return seek_frame_byte(s, stream_index, timestamp, flags);
if(stream_index < 0){
stream_index= av_find_default_stream_index(s);
if(s->iformat->read_timestamp && !(s->iformat->flags & AVFMT_NOBINSEARCH))
return av_seek_frame_binary(s, stream_index, timestamp, flags);
else if (!(s->iformat->flags & AVFMT_NOGENSEARCH))
- return av_seek_frame_generic(s, stream_index, timestamp, flags);
+ return seek_frame_generic(s, stream_index, timestamp, flags);
else
return -1;
}
if(s->iformat->read_seek || 1)
return av_seek_frame(s, stream_index, ts, flags | (ts - min_ts > (uint64_t)(max_ts - ts) ? AVSEEK_FLAG_BACKWARD : 0));
- // try some generic seek like av_seek_frame_generic() but with new ts semantics
+ // try some generic seek like seek_frame_generic() but with new ts semantics
}
/*******************************************************/
*
* @return TRUE if the stream has accurate duration for at least one component.
*/
-static int av_has_duration(AVFormatContext *ic)
+static int has_duration(AVFormatContext *ic)
{
int i;
AVStream *st;
*
* Also computes the global bitrate if possible.
*/
-static void av_update_stream_timings(AVFormatContext *ic)
+static void update_stream_timings(AVFormatContext *ic)
{
- int64_t start_time, start_time1, end_time, end_time1;
+ int64_t start_time, start_time1, start_time_text, end_time, end_time1;
int64_t duration, duration1;
int i;
AVStream *st;
start_time = INT64_MAX;
+ start_time_text = INT64_MAX;
end_time = INT64_MIN;
duration = INT64_MIN;
for(i = 0;i < ic->nb_streams; i++) {
st = ic->streams[i];
if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) {
start_time1= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
+ if (st->codec->codec_id == CODEC_ID_DVB_TELETEXT) {
+ if (start_time1 < start_time_text)
+ start_time_text = start_time1;
+ } else
if (start_time1 < start_time)
start_time = start_time1;
if (st->duration != AV_NOPTS_VALUE) {
duration = duration1;
}
}
+ if (start_time == INT64_MAX || (start_time > start_time_text && start_time - start_time_text < AV_TIME_BASE))
+ start_time = start_time_text;
if (start_time != INT64_MAX) {
ic->start_time = start_time;
if (end_time != INT64_MIN) {
int i;
AVStream *st;
- av_update_stream_timings(ic);
+ update_stream_timings(ic);
for(i = 0;i < ic->nb_streams; i++) {
st = ic->streams[i];
if (st->start_time == AV_NOPTS_VALUE) {
}
}
-static void av_estimate_timings_from_bit_rate(AVFormatContext *ic)
+static void estimate_timings_from_bit_rate(AVFormatContext *ic)
{
int64_t filesize, duration;
int bit_rate, i;
#define DURATION_MAX_RETRY 3
/* only usable for MPEG-PS streams */
-static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
+static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
{
AVPacket pkt1, *pkt = &pkt1;
AVStream *st;
for (i=0; i<ic->nb_streams; i++) {
st = ic->streams[i];
if (st->start_time == AV_NOPTS_VALUE && st->first_dts == AV_NOPTS_VALUE)
- av_log(st->codec, AV_LOG_WARNING, "start time is not set in av_estimate_timings_from_pts\n");
+ av_log(st->codec, AV_LOG_WARNING, "start time is not set in estimate_timings_from_pts\n");
if (st->parser) {
av_parser_close(st->parser);
}
}
-static void av_estimate_timings(AVFormatContext *ic, int64_t old_offset)
+static void estimate_timings(AVFormatContext *ic, int64_t old_offset)
{
int64_t file_size;
!strcmp(ic->iformat->name, "mpegts")) &&
file_size && ic->pb->seekable) {
/* get accurate estimate from the PTSes */
- av_estimate_timings_from_pts(ic, old_offset);
- } else if (av_has_duration(ic)) {
+ estimate_timings_from_pts(ic, old_offset);
+ } else if (has_duration(ic)) {
/* at least one component has timings - we use them for all
the components */
fill_all_stream_timings(ic);
} else {
av_log(ic, AV_LOG_WARNING, "Estimating duration from bitrate, this may be inaccurate\n");
/* less precise: use bitrate info */
- av_estimate_timings_from_bit_rate(ic);
+ estimate_timings_from_bit_rate(ic);
}
- av_update_stream_timings(ic);
+ update_stream_timings(ic);
+#if 0
{
int i;
AVStream av_unused *st;
for(i = 0;i < ic->nb_streams; i++) {
st = ic->streams[i];
- av_dlog(ic, "%d: start_time: %0.3f duration: %0.3f\n", i,
- (double) st->start_time / AV_TIME_BASE,
- (double) st->duration / AV_TIME_BASE);
+ printf("%d: start_time: %0.3f duration: %0.3f\n",
+ i, (double)st->start_time / AV_TIME_BASE,
+ (double)st->duration / AV_TIME_BASE);
}
- av_dlog(ic, "stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n",
- (double) ic->start_time / AV_TIME_BASE,
- (double) ic->duration / AV_TIME_BASE,
- ic->bit_rate / 1000);
+ printf("stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n",
+ (double)ic->start_time / AV_TIME_BASE,
+ (double)ic->duration / AV_TIME_BASE,
+ ic->bit_rate / 1000);
}
+#endif
}
-static int has_codec_parameters(AVCodecContext *enc)
+static int has_codec_parameters(AVCodecContext *avctx)
{
int val;
- switch(enc->codec_type) {
+ switch (avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- val = enc->sample_rate && enc->channels && enc->sample_fmt != AV_SAMPLE_FMT_NONE;
- if(!enc->frame_size &&
- (enc->codec_id == CODEC_ID_VORBIS ||
- enc->codec_id == CODEC_ID_AAC ||
- enc->codec_id == CODEC_ID_MP1 ||
- enc->codec_id == CODEC_ID_MP2 ||
- enc->codec_id == CODEC_ID_MP3 ||
- enc->codec_id == CODEC_ID_SPEEX))
+ val = avctx->sample_rate && avctx->channels && avctx->sample_fmt != AV_SAMPLE_FMT_NONE;
+ if(!avctx->frame_size &&
+ (avctx->codec_id == CODEC_ID_VORBIS ||
+ avctx->codec_id == CODEC_ID_AAC ||
+ avctx->codec_id == CODEC_ID_MP1 ||
+ avctx->codec_id == CODEC_ID_MP2 ||
+ avctx->codec_id == CODEC_ID_MP3 ||
+ avctx->codec_id == CODEC_ID_SPEEX ||
+ avctx->codec_id == CODEC_ID_CELT))
return 0;
break;
case AVMEDIA_TYPE_VIDEO:
- val = enc->width && enc->pix_fmt != PIX_FMT_NONE;
+ val = avctx->width && avctx->pix_fmt != PIX_FMT_NONE;
break;
default:
val = 1;
break;
}
- return enc->codec_id != CODEC_ID_NONE && val != 0;
+ return avctx->codec_id != CODEC_ID_NONE && val != 0;
}
static int has_decode_delay_been_guessed(AVStream *st)
st->codec_info_nb_frames >= 6 + st->codec->has_b_frames;
}
-static int try_decode_frame(AVStream *st, AVPacket *avpkt)
+static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **options)
{
int16_t *samples;
AVCodec *codec;
codec = avcodec_find_decoder(st->codec->codec_id);
if (!codec)
return -1;
- ret = avcodec_open(st->codec, codec);
+ ret = avcodec_open2(st->codec, codec, options);
if (ret < 0)
return ret;
}
- if(!has_codec_parameters(st->codec) || !has_decode_delay_been_guessed(st)){
+ if(!has_codec_parameters(st->codec) || !has_decode_delay_been_guessed(st) ||
+ (!st->codec_info_nb_frames && st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF)) {
switch(st->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
avcodec_get_frame_defaults(&picture);
return 0;
}
+#if FF_API_FORMAT_PARAMETERS
int av_find_stream_info(AVFormatContext *ic)
+{
+ return avformat_find_stream_info(ic, NULL);
+}
+#endif
+
+int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{
int i, count, ret, read_size, j;
AVStream *st;
AVPacket pkt1, *pkt;
int64_t old_offset = avio_tell(ic->pb);
+ int orig_nb_streams = ic->nb_streams; // new streams might appear, no options for those
for(i=0;i<ic->nb_streams;i++) {
AVCodec *codec;
st = ic->streams[i];
- if (st->codec->codec_id == CODEC_ID_AAC) {
+ if (st->codec->codec_id == CODEC_ID_AAC && st->codec->extradata_size) {
+ // We need to discard these since they can be plain wrong for
+ // backwards compatible HE-AAC signaling.
+ // But when we have no extradata we need to keep them or we can't
+ // play anything at all.
st->codec->sample_rate = 0;
st->codec->frame_size = 0;
st->codec->channels = 0;
}
+
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
/* if(!st->time_base.num)
assert(!st->codec->codec);
codec = avcodec_find_decoder(st->codec->codec_id);
- /* Force decoding of at least one frame of codec data
- * this makes sure the codec initializes the channel configuration
- * and does not trust the values from the container.
- */
- if (codec && codec->capabilities & CODEC_CAP_CHANNEL_CONF)
- st->codec->channels = 0;
-
/* Ensure that subtitle_header is properly set. */
if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE
&& codec && !st->codec->codec)
- avcodec_open(st->codec, codec);
+ avcodec_open2(st->codec, codec, options ? &options[i] : NULL);
//try to just open decoders, in case this is enough to get parameters
if(!has_codec_parameters(st->codec)){
if (codec && !st->codec->codec)
- avcodec_open(st->codec, codec);
+ avcodec_open2(st->codec, codec, options ? &options[i] : NULL);
}
}
/* NOTE: a new stream can be added there if no header in file
(AVFMTCTX_NOHEADER) */
- ret = av_read_frame_internal(ic, &pkt1);
- if (ret < 0 && ret != AVERROR(EAGAIN)) {
+ ret = read_frame_internal(ic, &pkt1);
+ if (ret == AVERROR(EAGAIN))
+ continue;
+
+ if (ret < 0) {
/* EOF or error */
ret = -1; /* we could not have all the codec parameters before EOF */
for(i=0;i<ic->nb_streams;i++) {
break;
}
- if (ret == AVERROR(EAGAIN))
- continue;
-
pkt= add_to_pktbuf(&ic->packet_buffer, &pkt1, &ic->packet_buffer_end);
if ((ret = av_dup_packet(pkt)) < 0)
goto find_stream_info_err;
st = ic->streams[pkt->stream_index];
if (st->codec_info_nb_frames>1) {
- if (st->time_base.den > 0 && av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration) {
- av_log(ic, AV_LOG_WARNING, "max_analyze_duration reached\n");
+ int64_t t;
+ if (st->time_base.den > 0 && (t=av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q)) >= ic->max_analyze_duration) {
+ av_log(ic, AV_LOG_WARNING, "max_analyze_duration %d reached at %"PRId64"\n", ic->max_analyze_duration, t);
break;
}
st->info->codec_info_duration += pkt->duration;
/* if still no information, we try to open the codec and to
decompress the frame. We try to avoid that in most cases as
it takes longer and uses more memory. For MPEG-4, we need to
- decompress for QuickTime. */
- if (!has_codec_parameters(st->codec) || !has_decode_delay_been_guessed(st))
- try_decode_frame(st, pkt);
+ decompress for QuickTime.
+
+ If CODEC_CAP_CHANNEL_CONF is set this will force decoding of at
+ least one frame of codec data, this makes sure the codec initializes
+ the channel configuration and does not only trust the values from the container.
+ */
+ try_decode_frame(st, pkt, (options && i < orig_nb_streams )? &options[i] : NULL);
st->codec_info_nb_frames++;
count++;
(st->codec_info_nb_frames-2)*(int64_t)st->time_base.den,
st->info->codec_info_duration*(int64_t)st->time_base.num, 60000);
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample)
- st->codec->codec_tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
+ if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample){
+ uint32_t tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
+ if(ff_find_pix_fmt(ff_raw_pix_fmt_tags, tag) == st->codec->pix_fmt)
+ st->codec->codec_tag= tag;
+ }
// the check for tb_unreliable() is not completely correct, since this is not about handling
// a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.
// ipmovie.c produces.
- if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > 1 && !st->r_frame_rate.num)
+ if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num)
av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX);
if (st->info->duration_count && !st->r_frame_rate.num
&& tb_unreliable(st->codec) /*&&
}
}
- av_estimate_timings(ic, old_offset);
+ estimate_timings(ic, old_offset);
compute_chapters_end(ic);
return NULL;
}
- st->codec= avcodec_alloc_context();
+ st->codec = avcodec_alloc_context3(NULL);
if (s->iformat) {
/* no default bitrate if decoding */
st->codec->bit_rate = 0;
/************************************************************/
/* output media file */
+#if FF_API_FORMAT_PARAMETERS
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)
} else
s->priv_data = NULL;
- if (s->oformat->set_parameters) {
- ret = s->oformat->set_parameters(s, ap);
- if (ret < 0)
- return ret;
+ return 0;
+}
+#endif
+
+int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat,
+ const char *format, const char *filename)
+{
+ AVFormatContext *s = avformat_alloc_context();
+ int ret = 0;
+
+ *avctx = NULL;
+ if (!s)
+ goto nomem;
+
+ if (!oformat) {
+ if (format) {
+ oformat = av_guess_format(format, NULL, NULL);
+ if (!oformat) {
+ av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
+ ret = AVERROR(EINVAL);
+ goto error;
+ }
+ } else {
+ oformat = av_guess_format(NULL, filename, NULL);
+ if (!oformat) {
+ ret = AVERROR(EINVAL);
+ av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n",
+ filename);
+ goto error;
+ }
+ }
}
+
+ s->oformat = oformat;
+ if (s->oformat->priv_data_size > 0) {
+ s->priv_data = av_mallocz(s->oformat->priv_data_size);
+ if (!s->priv_data)
+ goto nomem;
+ if (s->oformat->priv_class) {
+ *(const AVClass**)s->priv_data= s->oformat->priv_class;
+ av_opt_set_defaults(s->priv_data);
+ }
+ } else
+ s->priv_data = NULL;
+
+ if (filename)
+ av_strlcpy(s->filename, filename, sizeof(s->filename));
+ *avctx = s;
return 0;
+nomem:
+ av_log(s, AV_LOG_ERROR, "Out of memory\n");
+ ret = AVERROR(ENOMEM);
+error:
+ avformat_free_context(s);
+ return ret;
+}
+
+#if FF_API_ALLOC_OUTPUT_CONTEXT
+AVFormatContext *avformat_alloc_output_context(const char *format,
+ AVOutputFormat *oformat, const char *filename)
+{
+ AVFormatContext *avctx;
+ int ret = avformat_alloc_output_context2(&avctx, oformat, format, filename);
+ return ret < 0 ? NULL : avctx;
}
+#endif
static int validate_codec_tag(AVFormatContext *s, AVStream *st)
{
return 1;
}
+#if FF_API_FORMAT_PARAMETERS
int av_write_header(AVFormatContext *s)
{
- int ret, i;
+ return avformat_write_header(s, NULL);
+}
+#endif
+
+int avformat_write_header(AVFormatContext *s, AVDictionary **options)
+{
+ int ret = 0, i;
AVStream *st;
+ AVDictionary *tmp = NULL;
+
+ if (options)
+ av_dict_copy(&tmp, *options, 0);
+ if ((ret = av_opt_set_dict(s, &tmp)) < 0)
+ goto fail;
+ if (s->priv_data && s->oformat->priv_class && *(const AVClass**)s->priv_data==s->oformat->priv_class &&
+ (ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
+ goto fail;
// some sanity checks
if (s->nb_streams == 0 && !(s->oformat->flags & AVFMT_NOSTREAMS)) {
av_log(s, AV_LOG_ERROR, "no streams\n");
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
for(i=0;i<s->nb_streams;i++) {
case AVMEDIA_TYPE_AUDIO:
if(st->codec->sample_rate<=0){
av_log(s, AV_LOG_ERROR, "sample rate not set\n");
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
if(!st->codec->block_align)
st->codec->block_align = st->codec->channels *
case AVMEDIA_TYPE_VIDEO:
if(st->codec->time_base.num<=0 || st->codec->time_base.den<=0){ //FIXME audio too?
av_log(s, AV_LOG_ERROR, "time base not set\n");
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
if((st->codec->width<=0 || st->codec->height<=0) && !(s->oformat->flags & AVFMT_NODIMENSIONS)){
av_log(s, AV_LOG_ERROR, "dimensions not set\n");
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
if(av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)){
av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between encoder and muxer layer\n");
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
break;
}
av_log(s, AV_LOG_ERROR,
"Tag %s/0x%08x incompatible with output codec id '%d'\n",
tagbuf, st->codec->codec_tag, st->codec->codec_id);
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
}else
st->codec->codec_tag= av_codec_get_tag(s->oformat->codec_tag, st->codec->codec_id);
if (!s->priv_data && s->oformat->priv_data_size > 0) {
s->priv_data = av_mallocz(s->oformat->priv_data_size);
- if (!s->priv_data)
- return AVERROR(ENOMEM);
+ if (!s->priv_data) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ if (s->oformat->priv_class) {
+ *(const AVClass**)s->priv_data= s->oformat->priv_class;
+ av_opt_set_defaults(s->priv_data);
+ if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
+ goto fail;
+ }
}
/* set muxer identification string */
if(s->oformat->write_header){
ret = s->oformat->write_header(s);
if (ret < 0)
- return ret;
+ goto fail;
}
/* init PTS generation */
break;
}
if (den != AV_NOPTS_VALUE) {
- if (den <= 0)
- return AVERROR_INVALIDDATA;
- av_frac_init(&st->pts, 0, 0, den);
+ if (den <= 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ frac_init(&st->pts, 0, 0, den);
}
}
+
+ if (options) {
+ av_dict_free(options);
+ *options = tmp;
+ }
return 0;
+fail:
+ av_dict_free(&tmp);
+ return ret;
}
//FIXME merge with compute_pkt_fields
pkt->dts= st->pts_buffer[0];
}
- if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && st->cur_dts >= pkt->dts){
+ if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && ((!(s->oformat->flags & AVFMT_TS_NONSTRICT) && st->cur_dts >= pkt->dts) || st->cur_dts > pkt->dts)){
av_log(s, AV_LOG_ERROR,
"Application provided invalid, non monotonically increasing dts to muxer in stream %d: %"PRId64" >= %"PRId64"\n",
st->index, st->cur_dts, pkt->dts);
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);
+ frac_add(&st->pts, (int64_t)st->time_base.den * frame_size);
}
break;
case AVMEDIA_TYPE_VIDEO:
- av_frac_add(&st->pts, (int64_t)st->time_base.den * st->codec->time_base.num);
+ frac_add(&st->pts, (int64_t)st->time_base.den * st->codec->time_base.num);
break;
default:
break;
return ret;
ret= s->oformat->write_packet(s, pkt);
+
+ if (ret >= 0)
+ s->streams[pkt->stream_index]->nb_frames++;
return ret;
}
* @return 1 if a packet was output, 0 if no packet could be output,
* < 0 if an error occurred
*/
-static int av_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int flush){
+static int 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
for(;;){
AVPacket opkt;
- int ret= av_interleave_packet(s, &opkt, pkt, 0);
+ int ret= interleave_packet(s, &opkt, pkt, 0);
if(ret<=0) //FIXME cleanup needed for ret<0 ?
return ret;
ret= s->oformat->write_packet(s, &opkt);
+ if (ret >= 0)
+ s->streams[opkt.stream_index]->nb_frames++;
av_free_packet(&opkt);
pkt= NULL;
if(ret<0)
return ret;
+ if(url_ferror(s->pb))
+ return url_ferror(s->pb);
}
}
for(;;){
AVPacket pkt;
- ret= av_interleave_packet(s, &pkt, NULL, 1);
+ ret= interleave_packet(s, &pkt, NULL, 1);
if(ret<0) //FIXME cleanup needed for ret<0 ?
goto fail;
if(!ret)
break;
ret= s->oformat->write_packet(s, &pkt);
+ if (ret >= 0)
+ s->streams[pkt.stream_index]->nb_frames++;
av_free_packet(&pkt);
if(ret<0)
goto fail;
+ if(url_ferror(s->pb))
+ goto fail;
}
if(s->oformat->write_trailer)
ret = s->oformat->write_trailer(s);
fail:
+ if(ret == 0)
+ ret=url_ferror(s->pb);
for(i=0;i<s->nb_streams;i++) {
av_freep(&s->streams[i]->priv_data);
av_freep(&s->streams[i]->index_entries);
return ret;
}
+int av_get_output_timestamp(struct AVFormatContext *s, int stream,
+ int64_t *dts, int64_t *wall)
+{
+ if (!s->oformat || !s->oformat->get_output_timestamp)
+ return AVERROR(ENOSYS);
+ s->oformat->get_output_timestamp(s, stream, dts, wall);
+ return 0;
+}
+
void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx)
{
int i, j;
av_log(ctx, AV_LOG_INFO, "%sMetadata:\n", indent);
while((tag=av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
- if(strcmp("language", tag->key))
- av_log(ctx, AV_LOG_INFO, "%s %-16s: %s\n", indent, tag->key, tag->value);
+ if(strcmp("language", tag->key)){
+ char tmp[256];
+ int i;
+ av_strlcpy(tmp, tag->value, sizeof(tmp));
+ for(i=0; i<strlen(tmp); i++) if(tmp[i]==0xd) tmp[i]=' ';
+ av_log(ctx, AV_LOG_INFO, "%s %-16s: %s\n", indent, tag->key, tmp);
+ }
}
}
}
st->codec->width*st->sample_aspect_ratio.num,
st->codec->height*st->sample_aspect_ratio.den,
1024*1024);
- av_log(NULL, AV_LOG_INFO, ", PAR %d:%d DAR %d:%d",
+ av_log(NULL, AV_LOG_INFO, ", SAR %d:%d DAR %d:%d",
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
display_aspect_ratio.num, display_aspect_ratio.den);
}
}
av_strlcat(buf, rel, size);
}
+
+int64_t ff_iso8601_to_unix_time(const char *datestr)
+{
+#if HAVE_STRPTIME
+ struct tm time = {0};
+ strptime(datestr, "%Y - %m - %dT%T", &time);
+ return mktime(&time);
+#else
+ av_log(NULL, AV_LOG_WARNING, "strptime() unavailable on this system, cannot convert "
+ "the date string.\n");
+ return 0;
+#endif
+}