Newer
Older
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* This library 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 of the License, or (at your option) any later version.
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "allformats.h"
Philip Gladstone
committed
#undef NDEBUG
#include <assert.h>
Daniel Kristjansson
committed
/**
* @file libavformat/utils.c
* Various utility functions for using ffmpeg library.
*/
static void av_frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den);
static void av_frac_add(AVFrac *f, int64_t incr);
static void av_frac_set(AVFrac *f, int64_t val);
Daniel Kristjansson
committed
/** head of registered input format linked list. */
Michael Niedermayer
committed
AVInputFormat *first_iformat = NULL;
Daniel Kristjansson
committed
/** head of registered output format linked list. */
Michael Niedermayer
committed
AVOutputFormat *first_oformat = NULL;
Daniel Kristjansson
committed
/** head of registered image format linked list. */
Michael Niedermayer
committed
AVImageFormat *first_image_format = NULL;
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;
}
Fabrice Bellard
committed
int match_ext(const char *filename, const char *extensions)
ext = strrchr(filename, '.');
if (ext) {
ext++;
p = extensions;
for(;;) {
q = ext1;
while (*p != '\0' && *p != ',' && q-ext1<sizeof(ext1)-1)
AVOutputFormat *guess_format(const char *short_name, const char *filename,
Fabrice Bellard
committed
const char *mime_type)
Fabrice Bellard
committed
AVOutputFormat *fmt, *fmt_found;
#ifdef CONFIG_IMAGE2_MUXER
if (!short_name && filename &&
Michel Bardiaux
committed
av_filename_number_test(filename) &&
av_guess_image2_codec(filename) != CODEC_ID_NONE) {
return guess_format("image2", NULL, NULL);
}
if (!short_name && filename &&
Michel Bardiaux
committed
av_filename_number_test(filename) &&
guess_image_format(filename)) {
return guess_format("image", NULL, NULL);
}
/* find the proper file type */
fmt_found = NULL;
score_max = 0;
Fabrice Bellard
committed
fmt = first_oformat;
while (fmt != NULL) {
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 &&
match_ext(filename, fmt->extensions)) {
score += 5;
}
if (score > score_max) {
score_max = score;
fmt_found = fmt;
}
fmt = fmt->next;
}
return fmt_found;
AVOutputFormat *guess_stream_format(const char *short_name, const char *filename,
Philip Gladstone
committed
const char *mime_type)
{
AVOutputFormat *fmt = guess_format(short_name, filename, mime_type);
if (fmt) {
AVOutputFormat *stream_fmt;
char stream_format_name[64];
snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
stream_fmt = guess_format(stream_format_name, NULL, NULL);
if (stream_fmt)
fmt = stream_fmt;
}
return fmt;
}
Daniel Kristjansson
committed
* Guesses the codec id based upon muxer and filename.
enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
const char *filename, const char *mime_type, enum CodecType type){
if(type == CODEC_TYPE_VIDEO){
enum CodecID codec_id= CODEC_ID_NONE;
#ifdef CONFIG_IMAGE2_MUXER
if(!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")){
codec_id= av_guess_image2_codec(filename);
}
if(codec_id == CODEC_ID_NONE)
codec_id= fmt->video_codec;
return codec_id;
}else if(type == CODEC_TYPE_AUDIO)
return fmt->audio_codec;
else
return CODEC_ID_NONE;
}
Daniel Kristjansson
committed
/**
* finds AVInputFormat based on input format's short name.
*/
Fabrice Bellard
committed
AVInputFormat *av_find_input_format(const char *short_name)
{
AVInputFormat *fmt;
for(fmt = first_iformat; fmt != NULL; fmt = fmt->next) {
if (!strcmp(fmt->name, short_name))
return fmt;
}
return NULL;
}
Daniel Kristjansson
committed
* Default packet destructor.
Michael Niedermayer
committed
void av_destruct_packet(AVPacket *pkt)
{
av_free(pkt->data);
pkt->data = NULL; pkt->size = 0;
}
Fabrice Bellard
committed
/**
* Allocate the payload of a packet and intialized its fields to default values.
*
* @param pkt packet
* @param size wanted payload size
* @return 0 if OK. AVERROR_xxx otherwise.
Fabrice Bellard
committed
*/
void *data;
if((unsigned)size > (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE)
data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
Fabrice Bellard
committed
return AVERROR_NOMEM;
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
av_init_packet(pkt);
pkt->size = size;
pkt->destruct = av_destruct_packet;
/**
* Allocate and read the payload of a packet and intialized its fields to default values.
*
* @param pkt packet
* @param size wanted payload size
* @return >0 (read size) if OK. AVERROR_xxx otherwise.
*/
int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size)
{
int ret= av_new_packet(pkt, size);
if(ret<0)
return ret;
pkt->pos= url_ftell(s);
ret= get_buffer(s, pkt->data, size);
if(ret<=0)
av_free_packet(pkt);
else
pkt->size= ret;
return ret;
}
/* This is a hack - the packet memory allocation stuff is broken. The
packet is allocated if it was not really allocated */
int av_dup_packet(AVPacket *pkt)
{
if (pkt->destruct != av_destruct_packet) {
uint8_t *data;
/* we duplicate the packet and don't forget to put the padding
again */
if((unsigned)pkt->size > (unsigned)pkt->size + FF_INPUT_BUFFER_PADDING_SIZE)
data = av_malloc(pkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!data) {
return AVERROR_NOMEM;
}
memcpy(data, pkt->data, pkt->size);
memset(data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
pkt->data = data;
pkt->destruct = av_destruct_packet;
}
return 0;
}
Michel Bardiaux
committed
/**
* Allocate the payload of a packet and intialized its fields to default values.
*
* @param filename possible numbered sequence string
* @return 1 if a valid numbered sequence string, 0 otherwise.
*/
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
}
Daniel Kristjansson
committed
/**
* Guess file format.
*/
AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened)
Fabrice Bellard
committed
{
AVInputFormat *fmt1, *fmt;
int score, score_max;
fmt = NULL;
score_max = 0;
for(fmt1 = first_iformat; fmt1 != NULL; fmt1 = fmt1->next) {
if (!is_opened && !(fmt1->flags & AVFMT_NOFILE))
continue;
score = 0;
Philip Gladstone
committed
if (fmt1->read_probe) {
score = fmt1->read_probe(pd);
} else if (fmt1->extensions) {
Fabrice Bellard
committed
if (match_ext(pd->filename, fmt1->extensions)) {
score = 50;
}
Fabrice Bellard
committed
if (score > score_max) {
score_max = score;
fmt = fmt1;
}
}
return fmt;
}
/************************************************************/
/* input media file */
Daniel Kristjansson
committed
* Open a media file from an IO stream. 'fmt' must be specified.
if(fc->iformat) return fc->iformat->name;
else if(fc->oformat) return fc->oformat->name;
else return "NULL";
}
#define OFFSET(x) offsetof(AVFormatContext,x)
#define DEFAULT 0 //should be NAN but it doesnt work as its not a constant in glibc as required by ANSI/ISO C
//these names are too long to be readable
#define E AV_OPT_FLAG_ENCODING_PARAM
#define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[]={
{"probesize", NULL, OFFSET(probesize), FF_OPT_TYPE_INT, 32000, 32, INT_MAX, D}, /* 32000 from mpegts.c: 1.0 second at 24Mbit/s */
{"muxrate", "set mux rate", OFFSET(mux_rate), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, E},
{"packetsize", "set packet size", OFFSET(packet_size), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, E},
{"fflags", NULL, OFFSET(flags), FF_OPT_TYPE_FLAGS, DEFAULT, INT_MIN, INT_MAX, D, "fflags"},
{"ignidx", "ignore index", 0, FF_OPT_TYPE_CONST, AVFMT_FLAG_IGNIDX, INT_MIN, INT_MAX, D, "fflags"},
{"genpts", "generate pts", 0, FF_OPT_TYPE_CONST, AVFMT_FLAG_GENPTS, INT_MIN, INT_MAX, D, "fflags"},
{"track", " set the track number", OFFSET(track), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, E},
{"year", "set the year", OFFSET(year), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, E},
Panagiotis Issaris
committed
#undef E
#undef D
#undef DEFAULT
static const AVClass av_format_context_class = { "AVFormatContext", format_to_name, options };
#if LIBAVCODEC_VERSION_INT > ((52<<16)+(0<<8)+0)
static
#endif
void avformat_get_context_defaults(AVFormatContext *s){
memset(s, 0, sizeof(AVFormatContext));
s->av_class = &av_format_context_class;
av_opt_set_defaults(s);
AVFormatContext *av_alloc_format_context(void)
{
AVFormatContext *ic;
ic = av_malloc(sizeof(AVFormatContext));
if (!ic) return ic;
avformat_get_context_defaults(ic);
return ic;
}
Daniel Kristjansson
committed
/**
* Allocates all the structures needed to read an input stream.
* This does not open the needed codecs for decoding the stream[s].
*/
int av_open_input_stream(AVFormatContext **ic_ptr,
ByteIOContext *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));
}
if(!ap->prealloced_context)
ic = av_alloc_format_context();
else
ic = *ic_ptr;
if (!ic) {
err = AVERROR_NOMEM;
goto fail;
}
ic->iformat = fmt;
if (pb)
ic->pb = *pb;
ic->duration = AV_NOPTS_VALUE;
ic->start_time = AV_NOPTS_VALUE;
pstrcpy(ic->filename, sizeof(ic->filename), filename);
/* allocate private data */
if (fmt->priv_data_size > 0) {
ic->priv_data = av_mallocz(fmt->priv_data_size);
if (!ic->priv_data) {
err = AVERROR_NOMEM;
goto fail;
}
} else {
ic->priv_data = NULL;
}
err = ic->iformat->read_header(ic, ap);
if (err < 0)
goto fail;
if (pb)
ic->data_offset = url_ftell(&ic->pb);
*ic_ptr = ic;
return 0;
fail:
if (ic) {
av_freep(&ic->priv_data);
}
av_free(ic);
*ic_ptr = NULL;
return err;
}
Daniel Kristjansson
committed
/** 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
/**
* Open a media file as input. The codec are not opened. Only the file
* header (if present) is read.
*
* @param ic_ptr the opened media file handle is put here
* @param filename filename to open.
* @param fmt if non NULL, force the file format to use
* @param buf_size optional buffer size (zero if default is OK)
* @param ap additionnal parameters needed when opening the file (NULL if default)
* @return 0 if OK. AVERROR_xxx otherwise.
*/
int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
Fabrice Bellard
committed
AVInputFormat *fmt,
int buf_size,
AVFormatParameters *ap)
int err, must_open_file, file_opened, probe_size;
Fabrice Bellard
committed
AVProbeData probe_data, *pd = &probe_data;
ByteIOContext pb1, *pb = &pb1;
file_opened = 0;
pd->filename = "";
if (filename)
pd->filename = filename;
pd->buf = NULL;
Fabrice Bellard
committed
pd->buf_size = 0;
if (!fmt) {
/* guess format if no file can be opened */
/* do not open file if the format does not need it. XXX: specific
hack needed to handle RTSP/TCP */
must_open_file = 1;
if (fmt && (fmt->flags & AVFMT_NOFILE)) {
pb= NULL; //FIXME this or memset(pb, 0, sizeof(ByteIOContext)); otherwise its uninitalized
/* if no file needed do not try to open one */
if (url_fopen(pb, filename, URL_RDONLY) < 0) {
Fabrice Bellard
committed
err = AVERROR_IO;
Fabrice Bellard
committed
}
file_opened = 1;
url_setbufsize(pb, buf_size);
for(probe_size= PROBE_BUF_MIN; probe_size<=PROBE_BUF_MAX && !fmt; probe_size<<=1){
Fabrice Bellard
committed
/* read probe data */
pd->buf= av_realloc(pd->buf, probe_size);
pd->buf_size = get_buffer(pb, pd->buf, probe_size);
if (url_fseek(pb, 0, SEEK_SET) == (offset_t)-EPIPE) {
url_fclose(pb);
if (url_fopen(pb, filename, URL_RDONLY) < 0) {
Michael Niedermayer
committed
file_opened = 0;
err = AVERROR_IO;
goto fail;
}
}
/* guess file format */
fmt = av_probe_input_format(pd, 1);
Fabrice Bellard
committed
}
av_freep(&pd->buf);
Fabrice Bellard
committed
}
/* if still no format found, error */
if (!fmt) {
err = AVERROR_NOFMT;
goto fail;
/* XXX: suppress this hack for redirectors */
#ifdef CONFIG_NETWORK
if (fmt == &redir_demuxer) {
err = redir_open(ic_ptr, pb);
url_fclose(pb);
return err;
}
/* check filename in case of an image number is expected */
if (fmt->flags & AVFMT_NEEDNUMBER) {
Michel Bardiaux
committed
if (!av_filename_number_test(filename)) {
goto fail;
err = av_open_input_stream(ic_ptr, pb, filename, fmt, ap);
if (err)
goto fail;
Fabrice Bellard
committed
return 0;
av_freep(&pd->buf);
if (file_opened)
url_fclose(pb);
Fabrice Bellard
committed
*ic_ptr = NULL;
return err;
/*******************************************************/
Fabrice Bellard
committed
/**
Daniel Kristjansson
committed
* Read a transport packet from a media file.
*
* This function is absolete and should never be used.
* Use av_read_frame() instead.
Fabrice Bellard
committed
* @param s media file handle
* @param pkt is filled
* @return 0 if OK. AVERROR_xxx if error.
Fabrice Bellard
committed
*/
int av_read_packet(AVFormatContext *s, AVPacket *pkt)
{
return s->iformat->read_packet(s, pkt);
}
Loading
Loading full blame...