mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
split mux/demux related structures - added file probing support - improve media file reading API
Originally committed as revision 545 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
fe9cf0d44e
commit
b9a281db69
210
libav/avformat.h
210
libav/avformat.h
@ -24,10 +24,18 @@ int av_new_packet(AVPacket *pkt, int size);
|
||||
void av_free_packet(AVPacket *pkt);
|
||||
|
||||
/*************************************************/
|
||||
/* output formats */
|
||||
/* input/output formats */
|
||||
|
||||
struct AVFormatContext;
|
||||
struct AVFormatInputContext;
|
||||
|
||||
/* this structure contains the data a format has to probe a file */
|
||||
typedef struct AVProbeData {
|
||||
char *filename;
|
||||
unsigned char *buf;
|
||||
int buf_size;
|
||||
} AVProbeData;
|
||||
|
||||
#define AVPROBE_SCORE_MAX 100
|
||||
|
||||
typedef struct AVFormatParameters {
|
||||
int frame_rate;
|
||||
@ -38,12 +46,21 @@ typedef struct AVFormatParameters {
|
||||
enum PixelFormat pix_fmt;
|
||||
} AVFormatParameters;
|
||||
|
||||
typedef struct AVFormat {
|
||||
#define AVFMT_NOFILE 0x0001 /* no file should be opened */
|
||||
#define AVFMT_NEEDNUMBER 0x0002 /* needs '%d' in filename */
|
||||
#define AVFMT_NOHEADER 0x0004 /* signal that no header is present
|
||||
(streams are added dynamically) */
|
||||
#define AVFMT_SHOW_IDS 0x0008 /* show format stream IDs numbers */
|
||||
#define AVFMT_RGB24 0x0010 /* force RGB24 output for ppm (hack
|
||||
- need better api) */
|
||||
|
||||
typedef struct AVOutputFormat {
|
||||
const char *name;
|
||||
const char *long_name;
|
||||
const char *mime_type;
|
||||
const char *extensions; /* comma separated extensions */
|
||||
|
||||
/* size of private data so that it can be allocated in the wrapper */
|
||||
int priv_data_size;
|
||||
/* output support */
|
||||
enum CodecID audio_codec; /* default audio codec */
|
||||
enum CodecID video_codec; /* default video codec */
|
||||
@ -52,14 +69,28 @@ typedef struct AVFormat {
|
||||
int stream_index,
|
||||
unsigned char *buf, int size, int force_pts);
|
||||
int (*write_trailer)(struct AVFormatContext *);
|
||||
/* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */
|
||||
int flags;
|
||||
/* private fields */
|
||||
struct AVOutputFormat *next;
|
||||
} AVOutputFormat;
|
||||
|
||||
/* optional input support */
|
||||
/* read the format header and initialize the AVFormatInputContext
|
||||
typedef struct AVInputFormat {
|
||||
const char *name;
|
||||
const char *long_name;
|
||||
/* size of private data so that it can be allocated in the wrapper */
|
||||
int priv_data_size;
|
||||
/* tell if a given file has a chance of being parsing by this format */
|
||||
int (*read_probe)(AVProbeData *);
|
||||
/* read the format header and initialize the AVFormatContext
|
||||
structure. Return 0 if OK. 'ap' if non NULL contains
|
||||
additionnal paramters. Only used in raw format right now */
|
||||
additionnal paramters. Only used in raw format right
|
||||
now. 'av_new_stream' should be called to create new streams. */
|
||||
int (*read_header)(struct AVFormatContext *,
|
||||
AVFormatParameters *ap);
|
||||
/* read one packet and put it in 'pkt'. pts and flags are also set */
|
||||
/* read one packet and put it in 'pkt'. pts and flags are also
|
||||
set. 'av_new_stream' can be called only if the flag
|
||||
AVFMT_NOHEADER is used. */
|
||||
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
|
||||
/* close the stream. The AVFormatContext and AVStreams are not
|
||||
freed by this function */
|
||||
@ -67,24 +98,37 @@ typedef struct AVFormat {
|
||||
/* seek at or before a given pts (given in microsecond). The pts
|
||||
origin is defined by the stream */
|
||||
int (*read_seek)(struct AVFormatContext *, INT64 pts);
|
||||
/* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_NOHEADER */
|
||||
int flags;
|
||||
#define AVFMT_NOFILE 0x0001 /* no file should be opened */
|
||||
#define AVFMT_NEEDNUMBER 0x0002 /* needs '%d' in filename */
|
||||
struct AVFormat *next;
|
||||
} AVFormat;
|
||||
/* if extensions are defined, then no probe is done. You should
|
||||
usually not use extension format guessing because it is not
|
||||
reliable enough */
|
||||
const char *extensions;
|
||||
/* general purpose read only value that the format can use */
|
||||
int value;
|
||||
/* private fields */
|
||||
struct AVInputFormat *next;
|
||||
} AVInputFormat;
|
||||
|
||||
typedef struct AVStream {
|
||||
int id; /* internal stream id */
|
||||
int index; /* stream index in AVFormatContext */
|
||||
int id; /* format specific stream id */
|
||||
AVCodecContext codec; /* codec context */
|
||||
int r_frame_rate; /* real frame rate of the stream */
|
||||
void *priv_data;
|
||||
/* internal data used in av_find_stream_info() */
|
||||
int codec_info_state;
|
||||
int codec_info_nb_repeat_frames;
|
||||
int codec_info_nb_real_frames;
|
||||
} AVStream;
|
||||
|
||||
#define MAX_STREAMS 20
|
||||
|
||||
/* format I/O context */
|
||||
typedef struct AVFormatContext {
|
||||
struct AVFormat *format;
|
||||
/* can only be iformat or oformat, not both at the same time */
|
||||
struct AVInputFormat *iformat;
|
||||
struct AVOutputFormat *oformat;
|
||||
void *priv_data;
|
||||
ByteIOContext pb;
|
||||
int nb_streams;
|
||||
@ -107,86 +151,76 @@ typedef struct AVPacketList {
|
||||
struct AVPacketList *next;
|
||||
} AVPacketList;
|
||||
|
||||
extern AVFormat *first_format;
|
||||
extern AVInputFormat *first_iformat;
|
||||
extern AVOutputFormat *first_oformat;
|
||||
|
||||
/* rv10enc.c */
|
||||
extern AVFormat rm_format;
|
||||
/* XXX: use automatic init with either ELF sections or C file parser */
|
||||
/* modules */
|
||||
|
||||
/* mpegmux.c */
|
||||
/* mpeg.c */
|
||||
#define AVF_FLAG_VCD 0x00000001 /* VCD compatible MPEG-PS */
|
||||
extern AVFormat mpeg_mux_format;
|
||||
int mpegps_init(void);
|
||||
|
||||
/* asfenc.c */
|
||||
extern AVFormat asf_format;
|
||||
/* mpegts.c */
|
||||
extern AVInputFormat mpegts_demux;
|
||||
int mpegts_init(void);
|
||||
|
||||
/* avienc.c */
|
||||
extern AVFormat avi_format;
|
||||
|
||||
/* mov.c */
|
||||
extern AVFormat mov_format;
|
||||
extern AVFormat mp4_format;
|
||||
|
||||
/* jpegenc.c */
|
||||
extern AVFormat mpjpeg_format;
|
||||
extern AVFormat jpeg_format;
|
||||
extern AVFormat single_jpeg_format;
|
||||
|
||||
/* swfenc.c */
|
||||
extern AVFormat swf_format;
|
||||
|
||||
/* gif.c */
|
||||
extern AVFormat gif_format;
|
||||
/* au.c */
|
||||
extern AVFormat au_format;
|
||||
|
||||
/* wav.c */
|
||||
extern AVFormat wav_format;
|
||||
/* rm.c */
|
||||
int rm_init(void);
|
||||
|
||||
/* crc.c */
|
||||
extern AVFormat crc_format;
|
||||
int crc_init(void);
|
||||
|
||||
/* img.c */
|
||||
extern AVFormat pgm_format;
|
||||
extern AVFormat ppm_format;
|
||||
extern AVFormat pgmyuv_format;
|
||||
extern AVFormat imgyuv_format;
|
||||
int img_init(void);
|
||||
|
||||
extern AVFormat pgmpipe_format;
|
||||
extern AVFormat pgmyuvpipe_format;
|
||||
extern AVFormat ppmpipe_format;
|
||||
/* asf.c */
|
||||
int asf_init(void);
|
||||
|
||||
/* avienc.c */
|
||||
int avienc_init(void);
|
||||
|
||||
/* avidec.c */
|
||||
int avidec_init(void);
|
||||
|
||||
/* swf.c */
|
||||
int swf_init(void);
|
||||
|
||||
/* mov.c */
|
||||
int mov_init(void);
|
||||
|
||||
/* jpeg.c */
|
||||
int jpeg_init(void);
|
||||
|
||||
/* gif.c */
|
||||
int gif_init(void);
|
||||
|
||||
/* au.c */
|
||||
int au_init(void);
|
||||
|
||||
/* wav.c */
|
||||
int wav_init(void);
|
||||
|
||||
/* raw.c */
|
||||
extern AVFormat mp2_format;
|
||||
extern AVFormat ac3_format;
|
||||
extern AVFormat h263_format;
|
||||
extern AVFormat mpeg1video_format;
|
||||
extern AVFormat mjpeg_format;
|
||||
extern AVFormat pcm_s16le_format;
|
||||
extern AVFormat pcm_s16be_format;
|
||||
extern AVFormat pcm_u16le_format;
|
||||
extern AVFormat pcm_u16be_format;
|
||||
extern AVFormat pcm_s8_format;
|
||||
extern AVFormat pcm_u8_format;
|
||||
extern AVFormat pcm_mulaw_format;
|
||||
extern AVFormat pcm_alaw_format;
|
||||
extern AVFormat rawvideo_format;
|
||||
int raw_init(void);
|
||||
|
||||
/* ffm.c */
|
||||
extern AVFormat ffm_format;
|
||||
|
||||
/* formats.c */
|
||||
int ffm_init(void);
|
||||
|
||||
/* utils.c */
|
||||
#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
|
||||
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
|
||||
|
||||
void register_avformat(AVFormat *format);
|
||||
AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type);
|
||||
void av_register_input_format(AVInputFormat *format);
|
||||
void av_register_output_format(AVOutputFormat *format);
|
||||
AVOutputFormat *guess_format(const char *short_name,
|
||||
const char *filename, const char *mime_type);
|
||||
|
||||
int strstart(const char *str, const char *val, const char **ptr);
|
||||
void nstrcpy(char *buf, int buf_size, const char *str);
|
||||
/* This does what strncpy ought to do. */
|
||||
void strlcpy(char *dst, const char *src, int dst_size);
|
||||
void pstrcpy(char *buf, int buf_size, const char *str);
|
||||
|
||||
int match_ext(const char *filename, const char *extensions);
|
||||
void av_hex_dump(UINT8 *buf, int size);
|
||||
|
||||
void register_all(void);
|
||||
|
||||
@ -203,14 +237,29 @@ int fifo_size(FifoBuffer *f, UINT8 *rptr);
|
||||
int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr);
|
||||
void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr);
|
||||
|
||||
AVFormatContext *av_open_input_file(const char *filename,
|
||||
const char *format_name,
|
||||
int buf_size,
|
||||
AVFormatParameters *ap);
|
||||
/* media file input */
|
||||
AVInputFormat *av_find_input_format(const char *short_name);
|
||||
int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
|
||||
AVInputFormat *fmt,
|
||||
int buf_size,
|
||||
AVFormatParameters *ap);
|
||||
|
||||
#define AVERROR_UNKNOWN (-1) /* unknown error */
|
||||
#define AVERROR_IO (-2) /* i/o error */
|
||||
#define AVERROR_NUMEXPECTED (-3) /* number syntax expected in filename */
|
||||
#define AVERROR_INVALIDDATA (-4) /* invalid data found */
|
||||
#define AVERROR_NOMEM (-5) /* not enough memory */
|
||||
#define AVERROR_NOFMT (-6) /* unknown format */
|
||||
|
||||
int av_find_stream_info(AVFormatContext *ic);
|
||||
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
|
||||
void av_close_input_file(AVFormatContext *s);
|
||||
AVStream *av_new_stream(AVFormatContext *s, int id);
|
||||
|
||||
/* media file output */
|
||||
int av_write_header(AVFormatContext *s);
|
||||
int av_write_packet(AVFormatContext *s, AVPacket *pkt, int force_pts);
|
||||
int av_write_trailer(AVFormatContext *s);
|
||||
|
||||
void dump_format(AVFormatContext *ic,
|
||||
int index,
|
||||
@ -230,10 +279,11 @@ int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info);
|
||||
|
||||
int get_frame_filename(char *buf, int buf_size,
|
||||
const char *path, int number);
|
||||
int filename_number_test(const char *filename);
|
||||
|
||||
/* grab/output specific */
|
||||
extern AVFormat video_grab_device_format;
|
||||
extern AVFormat audio_device_format;
|
||||
/* grab specific */
|
||||
int video_grab_init(void);
|
||||
int audio_init(void);
|
||||
|
||||
extern const char *v4l_device;
|
||||
extern const char *audio_device;
|
||||
|
639
libav/utils.c
639
libav/utils.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Various utilities for ffmpeg system
|
||||
* Copyright (c) 2000,2001 Gerard Lantau
|
||||
* Copyright (c) 2000, 2001, 2002 Gerard Lantau
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -29,12 +29,22 @@
|
||||
#include <sys/timeb.h>
|
||||
#endif
|
||||
|
||||
AVFormat *first_format;
|
||||
AVInputFormat *first_iformat;
|
||||
AVOutputFormat *first_oformat;
|
||||
|
||||
void register_avformat(AVFormat *format)
|
||||
void av_register_input_format(AVInputFormat *format)
|
||||
{
|
||||
AVFormat **p;
|
||||
p = &first_format;
|
||||
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;
|
||||
@ -64,15 +74,16 @@ int match_ext(const char *filename, const char *extensions)
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type)
|
||||
AVOutputFormat *guess_format(const char *short_name, const char *filename,
|
||||
const char *mime_type)
|
||||
{
|
||||
AVFormat *fmt, *fmt_found;
|
||||
AVOutputFormat *fmt, *fmt_found;
|
||||
int score_max, score;
|
||||
|
||||
/* find the proper file type */
|
||||
fmt_found = NULL;
|
||||
score_max = 0;
|
||||
fmt = first_format;
|
||||
fmt = first_oformat;
|
||||
while (fmt != NULL) {
|
||||
score = 0;
|
||||
if (fmt->name && short_name && !strcmp(fmt->name, short_name))
|
||||
@ -92,8 +103,26 @@ AVFormat *guess_format(const char *short_name, const char *filename, const char
|
||||
return fmt_found;
|
||||
}
|
||||
|
||||
/* return TRUE if val is a prefix of str. If it returns TRUE, ptr is
|
||||
set to the next character in 'str' after the prefix */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return TRUE if val is a prefix of str. If it returns TRUE, ptr is
|
||||
* set to the next character in 'str' after the prefix.
|
||||
*
|
||||
* @param str input string
|
||||
* @param val prefix to test
|
||||
* @param ptr updated after the prefix in str in there is a match
|
||||
* @return TRUE if there is a match
|
||||
*/
|
||||
int strstart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
@ -110,7 +139,17 @@ int strstart(const char *str, const char *val, const char **ptr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void nstrcpy(char *buf, int buf_size, const char *str)
|
||||
/**
|
||||
* Copy the string str to buf. If str length is bigger than buf_size -
|
||||
* 1 then it is clamped to buf_size - 1.
|
||||
* NOTE: this function does what strncpy should have done to be
|
||||
* useful. NEVER use strncpy.
|
||||
*
|
||||
* @param buf destination buffer
|
||||
* @param buf_size size of destination buffer
|
||||
* @param str source string
|
||||
*/
|
||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
||||
{
|
||||
int c;
|
||||
char *q = buf;
|
||||
@ -124,67 +163,34 @@ void nstrcpy(char *buf, int buf_size, const char *str)
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
void strlcpy(char *dst, const char *src, int len)
|
||||
{
|
||||
int slen = strlen(src) + 1;
|
||||
|
||||
if (slen <= len) {
|
||||
memcpy(dst, src, slen);
|
||||
} else {
|
||||
memcpy(dst, src, len - 1);
|
||||
dst[len - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void register_all(void)
|
||||
{
|
||||
avcodec_init();
|
||||
avcodec_register_all();
|
||||
|
||||
register_avformat(&mp2_format);
|
||||
register_avformat(&ac3_format);
|
||||
register_avformat(&mpeg_mux_format);
|
||||
register_avformat(&mpeg1video_format);
|
||||
register_avformat(&mjpeg_format);
|
||||
register_avformat(&h263_format);
|
||||
register_avformat(&rm_format);
|
||||
register_avformat(&asf_format);
|
||||
register_avformat(&avi_format);
|
||||
register_avformat(&mov_format);
|
||||
register_avformat(&mp4_format);
|
||||
register_avformat(&mpjpeg_format);
|
||||
register_avformat(&jpeg_format);
|
||||
register_avformat(&single_jpeg_format);
|
||||
register_avformat(&swf_format);
|
||||
register_avformat(&gif_format);
|
||||
register_avformat(&au_format);
|
||||
register_avformat(&wav_format);
|
||||
register_avformat(&crc_format);
|
||||
mpegps_init();
|
||||
mpegts_init();
|
||||
crc_init();
|
||||
img_init();
|
||||
raw_init();
|
||||
rm_init();
|
||||
asf_init();
|
||||
avienc_init();
|
||||
avidec_init();
|
||||
wav_init();
|
||||
swf_init();
|
||||
au_init();
|
||||
gif_init();
|
||||
mov_init();
|
||||
jpeg_init();
|
||||
|
||||
register_avformat(&pcm_s16le_format);
|
||||
register_avformat(&pcm_s16be_format);
|
||||
register_avformat(&pcm_u16le_format);
|
||||
register_avformat(&pcm_u16be_format);
|
||||
register_avformat(&pcm_s8_format);
|
||||
register_avformat(&pcm_u8_format);
|
||||
register_avformat(&pcm_mulaw_format);
|
||||
register_avformat(&pcm_alaw_format);
|
||||
register_avformat(&rawvideo_format);
|
||||
#ifndef CONFIG_WIN32
|
||||
register_avformat(&ffm_format);
|
||||
ffm_init();
|
||||
#endif
|
||||
register_avformat(&pgm_format);
|
||||
register_avformat(&ppm_format);
|
||||
register_avformat(&pgmyuv_format);
|
||||
register_avformat(&imgyuv_format);
|
||||
register_avformat(&pgmpipe_format);
|
||||
register_avformat(&pgmyuvpipe_format);
|
||||
register_avformat(&ppmpipe_format);
|
||||
#ifdef CONFIG_GRAB
|
||||
register_avformat(&video_grab_device_format);
|
||||
register_avformat(&audio_device_format);
|
||||
video_grab_init();
|
||||
audio_init();
|
||||
#endif
|
||||
|
||||
/* file protocols */
|
||||
register_protocol(&file_protocol);
|
||||
register_protocol(&pipe_protocol);
|
||||
@ -196,11 +202,18 @@ void register_all(void)
|
||||
|
||||
/* memory handling */
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int av_new_packet(AVPacket *pkt, int size)
|
||||
{
|
||||
pkt->data = av_malloc(size);
|
||||
if (!pkt->data)
|
||||
return -ENOMEM;
|
||||
return AVERROR_NOMEM;
|
||||
pkt->size = size;
|
||||
/* sane state */
|
||||
pkt->pts = 0;
|
||||
@ -209,6 +222,11 @@ int av_new_packet(AVPacket *pkt, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a packet
|
||||
*
|
||||
* @param pkt packet to free
|
||||
*/
|
||||
void av_free_packet(AVPacket *pkt)
|
||||
{
|
||||
av_freep(&pkt->data);
|
||||
@ -293,61 +311,146 @@ void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr)
|
||||
*wptr_ptr = wptr;
|
||||
}
|
||||
|
||||
/* media file handling.
|
||||
'filename' is the filename to open.
|
||||
'format_name' is used to force the file format (NULL if auto guess).
|
||||
'buf_size' is the optional buffer size (zero if default is OK).
|
||||
'ap' are additionnal parameters needed when opening the file (NULL if default).
|
||||
*/
|
||||
|
||||
AVFormatContext *av_open_input_file(const char *filename,
|
||||
const char *format_name,
|
||||
int buf_size,
|
||||
AVFormatParameters *ap)
|
||||
int filename_number_test(const char *filename)
|
||||
{
|
||||
char buf[1024];
|
||||
return get_frame_filename(buf, sizeof(buf), filename, 1);
|
||||
}
|
||||
|
||||
/* guess file format */
|
||||
static AVInputFormat *probe_input_format(AVProbeData *pd, int is_opened)
|
||||
{
|
||||
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;
|
||||
if (fmt1->extensions) {
|
||||
if (match_ext(pd->filename, fmt1->extensions)) {
|
||||
score = 50;
|
||||
}
|
||||
} else if (fmt1->read_probe) {
|
||||
score = fmt1->read_probe(pd);
|
||||
}
|
||||
if (score > score_max) {
|
||||
score_max = score;
|
||||
fmt = fmt1;
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
/* input media file */
|
||||
|
||||
#define PROBE_BUF_SIZE 2048
|
||||
|
||||
/**
|
||||
* 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,
|
||||
AVInputFormat *fmt,
|
||||
int buf_size,
|
||||
AVFormatParameters *ap)
|
||||
{
|
||||
AVFormat *fmt;
|
||||
AVFormatContext *ic = NULL;
|
||||
int err;
|
||||
char buf[PROBE_BUF_SIZE];
|
||||
AVProbeData probe_data, *pd = &probe_data;
|
||||
|
||||
ic = av_mallocz(sizeof(AVFormatContext));
|
||||
if (!ic)
|
||||
if (!ic) {
|
||||
err = AVERROR_NOMEM;
|
||||
goto fail;
|
||||
}
|
||||
pstrcpy(ic->filename, sizeof(ic->filename), filename);
|
||||
pd->filename = ic->filename;
|
||||
pd->buf = buf;
|
||||
pd->buf_size = 0;
|
||||
|
||||
/* find format */
|
||||
if (format_name != NULL) {
|
||||
fmt = guess_format(format_name, NULL, NULL);
|
||||
} else {
|
||||
fmt = guess_format(NULL, filename, NULL);
|
||||
if (!fmt) {
|
||||
/* guess format if no file can be opened */
|
||||
fmt = probe_input_format(pd, 0);
|
||||
}
|
||||
if (!fmt || !fmt->read_header) {
|
||||
return NULL;
|
||||
}
|
||||
ic->format = fmt;
|
||||
|
||||
/* if no file needed do not try to open one */
|
||||
if (!(fmt->flags & AVFMT_NOFILE)) {
|
||||
if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0)
|
||||
if (!fmt || !(fmt->flags & AVFMT_NOFILE)) {
|
||||
if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0) {
|
||||
err = AVERROR_IO;
|
||||
goto fail;
|
||||
}
|
||||
if (buf_size > 0) {
|
||||
url_setbufsize(&ic->pb, buf_size);
|
||||
}
|
||||
/* read probe data */
|
||||
pd->buf_size = get_buffer(&ic->pb, buf, PROBE_BUF_SIZE);
|
||||
url_fseek(&ic->pb, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
err = ic->format->read_header(ic, ap);
|
||||
if (err < 0) {
|
||||
if (!(fmt->flags & AVFMT_NOFILE)) {
|
||||
url_fclose(&ic->pb);
|
||||
}
|
||||
/* guess file format */
|
||||
if (!fmt) {
|
||||
fmt = probe_input_format(pd, 1);
|
||||
}
|
||||
|
||||
/* if still no format found, error */
|
||||
if (!fmt) {
|
||||
err = AVERROR_NOFMT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return ic;
|
||||
ic->iformat = fmt;
|
||||
|
||||
/* allocate private data */
|
||||
ic->priv_data = av_mallocz(fmt->priv_data_size);
|
||||
if (!ic->priv_data) {
|
||||
err = AVERROR_NOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check filename in case of an image number is expected */
|
||||
if (ic->iformat->flags & AVFMT_NEEDNUMBER) {
|
||||
if (filename_number_test(ic->filename) < 0) {
|
||||
err = AVERROR_NUMEXPECTED;
|
||||
goto fail1;
|
||||
}
|
||||
}
|
||||
|
||||
err = ic->iformat->read_header(ic, ap);
|
||||
if (err < 0)
|
||||
goto fail1;
|
||||
*ic_ptr = ic;
|
||||
return 0;
|
||||
fail1:
|
||||
if (!(fmt->flags & AVFMT_NOFILE)) {
|
||||
url_fclose(&ic->pb);
|
||||
}
|
||||
fail:
|
||||
if (ic) {
|
||||
av_free(ic->priv_data);
|
||||
}
|
||||
av_free(ic);
|
||||
return NULL;
|
||||
*ic_ptr = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a packet from a media file
|
||||
* @param s media file handle
|
||||
* @param pkt is filled
|
||||
* @return 0 if OK. AVERROR_xxx if error.
|
||||
*/
|
||||
int av_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
AVPacketList *pktl;
|
||||
@ -360,16 +463,240 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
av_free(pktl);
|
||||
return 0;
|
||||
} else {
|
||||
return s->format->read_packet(s, pkt);
|
||||
return s->iformat->read_packet(s, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
/* state for codec information */
|
||||
#define CSTATE_NOTFOUND 0
|
||||
#define CSTATE_DECODING 1
|
||||
#define CSTATE_FOUND 2
|
||||
|
||||
static int has_codec_parameters(AVCodecContext *enc)
|
||||
{
|
||||
int val;
|
||||
switch(enc->codec_type) {
|
||||
case CODEC_TYPE_AUDIO:
|
||||
val = enc->sample_rate;
|
||||
break;
|
||||
case CODEC_TYPE_VIDEO:
|
||||
val = enc->width;
|
||||
break;
|
||||
default:
|
||||
val = 1;
|
||||
break;
|
||||
}
|
||||
return (val != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the beginning of a media file to get stream information. This
|
||||
* is useful for file formats with no headers such as MPEG. This
|
||||
* function also compute the real frame rate in case of mpeg2 repeat
|
||||
* frame mode.
|
||||
*
|
||||
* @param ic media file handle
|
||||
* @return >=0 if OK. AVERROR_xxx if error.
|
||||
*/
|
||||
int av_find_stream_info(AVFormatContext *ic)
|
||||
{
|
||||
int i, count, ret, got_picture, size, read_size;
|
||||
AVCodec *codec;
|
||||
AVStream *st;
|
||||
AVPacket *pkt;
|
||||
AVPicture picture;
|
||||
AVPacketList *pktl=NULL, **ppktl;
|
||||
short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2];
|
||||
UINT8 *ptr;
|
||||
int min_read_size, max_read_size;
|
||||
|
||||
/* typical mpeg ts rate is 40 Mbits. DVD rate is about 10
|
||||
Mbits. We read at most 0.1 second of file to find all streams */
|
||||
|
||||
/* XXX: base it on stream bitrate when possible */
|
||||
if (ic->iformat == &mpegts_demux) {
|
||||
/* maximum number of bytes we accept to read to find all the streams
|
||||
in a file */
|
||||
min_read_size = 3000000;
|
||||
} else {
|
||||
min_read_size = 125000;
|
||||
}
|
||||
/* max read size is 2 seconds of video max */
|
||||
max_read_size = min_read_size * 20;
|
||||
|
||||
/* set initial codec state */
|
||||
for(i=0;i<ic->nb_streams;i++) {
|
||||
st = ic->streams[i];
|
||||
if (has_codec_parameters(&st->codec))
|
||||
st->codec_info_state = CSTATE_FOUND;
|
||||
else
|
||||
st->codec_info_state = CSTATE_NOTFOUND;
|
||||
st->codec_info_nb_repeat_frames = 0;
|
||||
st->codec_info_nb_real_frames = 0;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
read_size = 0;
|
||||
ppktl = &ic->packet_buffer;
|
||||
for(;;) {
|
||||
/* check if one codec still needs to be handled */
|
||||
for(i=0;i<ic->nb_streams;i++) {
|
||||
st = ic->streams[i];
|
||||
if (st->codec_info_state != CSTATE_FOUND)
|
||||
break;
|
||||
}
|
||||
if (i == ic->nb_streams) {
|
||||
/* NOTE: if the format has no header, then we need to read
|
||||
some packets to get most of the streams, so we cannot
|
||||
stop here */
|
||||
if (!(ic->iformat->flags & AVFMT_NOHEADER) ||
|
||||
read_size >= min_read_size) {
|
||||
/* if we found the info for all the codecs, we can stop */
|
||||
ret = count;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* we did not get all the codec info, but we read too much data */
|
||||
if (read_size >= max_read_size) {
|
||||
ret = count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pktl = av_mallocz(sizeof(AVPacketList));
|
||||
if (!pktl) {
|
||||
ret = AVERROR_NOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
/* add the packet in the buffered packet list */
|
||||
*ppktl = pktl;
|
||||
ppktl = &pktl->next;
|
||||
|
||||
/* NOTE: a new stream can be added there if no header in file
|
||||
(AVFMT_NOHEADER) */
|
||||
pkt = &pktl->pkt;
|
||||
if (ic->iformat->read_packet(ic, pkt) < 0) {
|
||||
/* EOF or error */
|
||||
ret = -1; /* we could not have all the codec parameters before EOF */
|
||||
if ((ic->iformat->flags & AVFMT_NOHEADER) &&
|
||||
i == ic->nb_streams)
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
read_size += pkt->size;
|
||||
|
||||
/* open new codecs */
|
||||
for(i=0;i<ic->nb_streams;i++) {
|
||||
st = ic->streams[i];
|
||||
if (st->codec_info_state == CSTATE_NOTFOUND) {
|
||||
/* set to found in case of error */
|
||||
st->codec_info_state = CSTATE_FOUND;
|
||||
codec = avcodec_find_decoder(st->codec.codec_id);
|
||||
if (codec) {
|
||||
ret = avcodec_open(&st->codec, codec);
|
||||
if (ret >= 0)
|
||||
st->codec_info_state = CSTATE_DECODING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st = ic->streams[pkt->stream_index];
|
||||
if (st->codec_info_state == CSTATE_DECODING) {
|
||||
/* decode the data and update codec parameters */
|
||||
ptr = pkt->data;
|
||||
size = pkt->size;
|
||||
while (size > 0) {
|
||||
switch(st->codec.codec_type) {
|
||||
case CODEC_TYPE_VIDEO:
|
||||
ret = avcodec_decode_video(&st->codec, &picture,
|
||||
&got_picture, ptr, size);
|
||||
break;
|
||||
case CODEC_TYPE_AUDIO:
|
||||
ret = avcodec_decode_audio(&st->codec, samples,
|
||||
&got_picture, ptr, size);
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
/* if error, simply ignore because another packet
|
||||
may be OK */
|
||||
break;
|
||||
}
|
||||
if (got_picture) {
|
||||
/* we got the parameters - now we can stop
|
||||
examining this stream */
|
||||
/* XXX: add a codec info so that we can decide if
|
||||
the codec can repeat frames */
|
||||
if (st->codec.codec_id == CODEC_ID_MPEG1VIDEO &&
|
||||
ic->iformat != &mpegts_demux &&
|
||||
st->codec.sub_id == 2) {
|
||||
/* for mpeg2 video, we want to know the real
|
||||
frame rate, so we decode 40 frames. In mpeg
|
||||
TS case we do not do it because it would be
|
||||
too long */
|
||||
st->codec_info_nb_real_frames++;
|
||||
st->codec_info_nb_repeat_frames += st->codec.repeat_pict;
|
||||
#if 0
|
||||
/* XXX: testing */
|
||||
if ((st->codec_info_nb_real_frames % 24) == 23) {
|
||||
st->codec_info_nb_repeat_frames += 2;
|
||||
}
|
||||
#endif
|
||||
/* stop after 40 frames */
|
||||
if (st->codec_info_nb_real_frames >= 40) {
|
||||
st->r_frame_rate = (st->codec.frame_rate *
|
||||
st->codec_info_nb_real_frames) /
|
||||
(st->codec_info_nb_real_frames +
|
||||
(st->codec_info_nb_repeat_frames >> 1));
|
||||
goto close_codec;
|
||||
}
|
||||
} else {
|
||||
close_codec:
|
||||
st->codec_info_state = CSTATE_FOUND;
|
||||
avcodec_close(&st->codec);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ptr += ret;
|
||||
size -= ret;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
/* close each codec if there are opened */
|
||||
for(i=0;i<ic->nb_streams;i++) {
|
||||
st = ic->streams[i];
|
||||
if (st->codec_info_state == CSTATE_DECODING)
|
||||
avcodec_close(&st->codec);
|
||||
}
|
||||
|
||||
/* set real frame rate info */
|
||||
for(i=0;i<ic->nb_streams;i++) {
|
||||
st = ic->streams[i];
|
||||
if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
|
||||
if (!st->r_frame_rate)
|
||||
st->r_frame_rate = st->codec.frame_rate;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a media file (but not its codecs)
|
||||
*
|
||||
* @param s media file handle
|
||||
*/
|
||||
void av_close_input_file(AVFormatContext *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (s->format->read_close)
|
||||
s->format->read_close(s);
|
||||
if (s->iformat->read_close)
|
||||
s->iformat->read_close(s);
|
||||
for(i=0;i<s->nb_streams;i++) {
|
||||
av_free(s->streams[i]);
|
||||
}
|
||||
@ -384,17 +711,81 @@ void av_close_input_file(AVFormatContext *s)
|
||||
}
|
||||
s->packet_buffer = NULL;
|
||||
}
|
||||
if (!(s->format->flags & AVFMT_NOFILE)) {
|
||||
if (!(s->iformat->flags & AVFMT_NOFILE)) {
|
||||
url_fclose(&s->pb);
|
||||
}
|
||||
av_free(s->priv_data);
|
||||
av_free(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new stream to a media file. Can only be called in the
|
||||
* read_header function. If the flag AVFMT_NOHEADER is in the format
|
||||
* description, then new streams can be added in read_packet too.
|
||||
*
|
||||
*
|
||||
* @param s media file handle
|
||||
* @param id file format dependent stream id
|
||||
*/
|
||||
AVStream *av_new_stream(AVFormatContext *s, int id)
|
||||
{
|
||||
AVStream *st;
|
||||
|
||||
if (s->nb_streams >= MAX_STREAMS)
|
||||
return NULL;
|
||||
|
||||
st = av_mallocz(sizeof(AVStream));
|
||||
if (!st)
|
||||
return NULL;
|
||||
st->index = s->nb_streams;
|
||||
st->id = id;
|
||||
s->streams[s->nb_streams++] = st;
|
||||
return st;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
/* output media file */
|
||||
|
||||
/**
|
||||
* allocate the stream private data and write the stream header to an
|
||||
* output media file
|
||||
*
|
||||
* @param s media file handle
|
||||
* @return 0 if OK. AVERROR_xxx if error.
|
||||
*/
|
||||
int av_write_header(AVFormatContext *s)
|
||||
{
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if (!s->priv_data)
|
||||
return AVERROR_NOMEM;
|
||||
return s->oformat->write_header(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* write a packet to an output media file
|
||||
*
|
||||
* @param s media file handle
|
||||
* @param pkt packet to write
|
||||
* @param force_pts XXX: need to suppress that
|
||||
*/
|
||||
int av_write_packet(AVFormatContext *s, AVPacket *pkt, int force_pts)
|
||||
{
|
||||
/* XXX: currently, an emulation because internal API must change */
|
||||
return s->format->write_packet(s, pkt->stream_index, pkt->data, pkt->size, force_pts);
|
||||
return s->oformat->write_packet(s, pkt->stream_index, pkt->data, pkt->size, force_pts);
|
||||
}
|
||||
|
||||
/**
|
||||
* write the stream trailer to an output media file and and free the
|
||||
* file private data.
|
||||
*
|
||||
* @param s media file handle
|
||||
* @return 0 if OK. AVERROR_xxx if error. */
|
||||
int av_write_trailer(AVFormatContext *s)
|
||||
{
|
||||
int ret;
|
||||
ret = s->oformat->write_trailer(s);
|
||||
av_freep(&s->priv_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* "user interface" functions */
|
||||
@ -404,17 +795,28 @@ void dump_format(AVFormatContext *ic,
|
||||
const char *url,
|
||||
int is_output)
|
||||
{
|
||||
int i;
|
||||
int i, flags;
|
||||
char buf[256];
|
||||
|
||||
fprintf(stderr, "%s #%d, %s, %s '%s':\n",
|
||||
is_output ? "Output" : "Input",
|
||||
index, ic->format->name,
|
||||
index,
|
||||
is_output ? ic->oformat->name : ic->iformat->name,
|
||||
is_output ? "to" : "from", url);
|
||||
for(i=0;i<ic->nb_streams;i++) {
|
||||
AVStream *st = ic->streams[i];
|
||||
avcodec_string(buf, sizeof(buf), &st->codec, is_output);
|
||||
fprintf(stderr, " Stream #%d.%d: %s\n", index, i, buf);
|
||||
fprintf(stderr, " Stream #%d.%d", index, i);
|
||||
/* the pid is an important information, so we display it */
|
||||
/* XXX: add a generic system */
|
||||
if (is_output)
|
||||
flags = ic->oformat->flags;
|
||||
else
|
||||
flags = ic->iformat->flags;
|
||||
if (flags & AVFMT_SHOW_IDS) {
|
||||
fprintf(stderr, "[0x%x]", st->id);
|
||||
}
|
||||
fprintf(stderr, ": %s\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,3 +1063,36 @@ void ticker_init(Ticker *tick, INT64 inrate, INT64 outrate)
|
||||
tick->div = tick->outrate / tick->inrate;
|
||||
tick->mod = tick->outrate % tick->inrate;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Print on stdout a nice hexa dump of a buffer
|
||||
* @param buf buffer
|
||||
* @param size buffer size
|
||||
*/
|
||||
void av_hex_dump(UINT8 *buf, int size)
|
||||
{
|
||||
int len, i, j, c;
|
||||
|
||||
for(i=0;i<size;i+=16) {
|
||||
len = size - i;
|
||||
if (len > 16)
|
||||
len = 16;
|
||||
printf("%08x ", i);
|
||||
for(j=0;j<16;j++) {
|
||||
if (j < len)
|
||||
printf(" %02x", buf[i+j]);
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf(" ");
|
||||
for(j=0;j<len;j++) {
|
||||
c = buf[i+j];
|
||||
if (c < ' ' || c > '~')
|
||||
c = '.';
|
||||
printf("%c", c);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user