#ifndef AVFORMAT_H
#define AVFORMAT_H

/*************************************************
** ʶļʽýͿʹõĺꡢݽṹͺ
**ͨЩꡢݽṹͺڴģȫЧ
*************************************************/
#ifdef __cplusplus

extern "C"
{
#endif

	/* 汾 */
#define LIBAVFORMAT_VERSION_INT ((50<<16)+(4<<8)+0)
#define LIBAVFORMAT_VERSION     50.4.0
#define LIBAVFORMAT_BUILD       LIBAVFORMAT_VERSION_INT

#define LIBAVFORMAT_IDENT       "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION)

	/* ͷļ */
#include "../libavcodec/avcodec.h"

	/* ioͷļ */
#include "avio.h"

	/* 붨 */
#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
#define AVERROR_NOTSUPP     (-7)	// operation not supported

	/* ļת */
#define AVSEEK_FLAG_BACKWARD 1		// seek backward
#define AVSEEK_FLAG_BYTE     2		// seeking based on position in bytes
#define AVSEEK_FLAG_ANY      4		// seek to any frame, even non keyframes

#define AVFMT_NOFILE        0x0001	// no file should be opened

#define PKT_FLAG_KEY		0x0001

#define AVINDEX_KEYFRAME	0x0001

#define AVPROBE_SCORE_MAX	100

#define MAX_STREAMS 20

	/*
	** ݰƵƵһһݰһ֡ݣ
	** δ֡
	*/
typedef struct AVPacket
{
    int64_t pts; // presentation time stamp in time_base units  ʾʱ䣬Ƶʾʱ
    int64_t dts; // decompression time stamp in time_base units  ʱ䣬ǺҪ
    int64_t pos; // byte position in stream, -1 if unknown
    uint8_t *data;								// ʵʱƵݻ׵ַ
    int size;											// ʵʱƵݻĴС
    int stream_index;							// ǰƵݰӦڱƵƵ
    int flags;										//ݰһЩǣǷǹؼ֡ȡ
    void(*destruct)(struct AVPacket*); // ٺ
} AVPacket;

/* Ƶб */
typedef struct AVPacketList
{
    AVPacket pkt;
    struct AVPacketList *next;
} AVPacketList;

/* ͷݰڵ */
static inline void av_destruct_packet(AVPacket *pkt)
{
    av_free(pkt->data);
    pkt->data = NULL;
    pkt->size = 0;
}

/* ͷһƵ */
static inline void av_free_packet(AVPacket *pkt)
{
    if (pkt && pkt->destruct)
        pkt->destruct(pkt);
}

/* 
** ȡһƵ
** ļݰݣ
** עܵʱļƫȷҪݵĴСҲȷ
** ݰĻûз䡣ڴҪʼһЩ 
*/
static inline int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size)
{
    int ret;
    unsigned char *data;
    if ((unsigned)size > (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE)
        return AVERROR_NOMEM;

	// ڴ
    data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
    if (!data)
        return AVERROR_NOMEM;

    memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);

    pkt->pts = AV_NOPTS_VALUE;
    pkt->dts = AV_NOPTS_VALUE;
    pkt->pos =  - 1;
    pkt->flags = 0;
    pkt->stream_index = 0;
    pkt->data = data;
    pkt->size = size;
    pkt->destruct = av_destruct_packet;

    pkt->pos = url_ftell(s);

	// ȡʵʵ
    ret = url_fread(s, pkt->data, size);
    if (ret <= 0)
        av_free_packet(pkt);
    else
        pkt->size = ret;

    return ret;
}

/* 
** ̽
** ΪʶļʽҪһļͷƥ ffplay ֵ֧ļʽļ
** ýṹļ׵ַʹС˴Ķļ
*/
typedef struct AVProbeData
{
	// ļ
    const char *filename;
	// ̽⵽
    unsigned char *buf;
	// ݳ 
    int buf_size;
} AVProbeData;

/* 
** ļṹflags  size λΪ˽ʡڴ
*/
typedef struct AVIndexEntry
{
    int64_t pos;
    int64_t timestamp;
    int flags: 2;
    int size: 30; //yeah trying to keep the size of this small to reduce memory requirements (its 24 vs 32 byte due to possible 8byte align)
} AVIndexEntry;

/* 
** ƵƵ 
** AVStream ıʾһýýһЩͨõ
** ϸΪƵƵƵֿԷֳAVIͣmp4
*/
typedef struct AVStream
{
	// 
    AVCodecContext *actx;  // codec context, change from AVCodecContext *codec;

	// 
    void *priv_data;       // AVIStream ڱУ AVIStream

	// ʱ׼
    AVRational time_base; //  av_set_pts_info()ʼ

	// 󣬼粻֧Ĳҵʱʹ
    AVIndexEntry *index_entries; // only used if the format does not support seeking natively
    int nb_index_entries;
    int index_entries_allocated_size;

    double frame_last_delay; // ֡ӳ
} AVStream;

/* ʽ */
typedef struct AVFormatParameters
{
    int dbg; //only for debug ֻһԱ־
} AVFormatParameters;

/* 
** ʽļĽṹָ룩 
** AVInputFormat ļʽעⲻAVIAV Inputڹܺ
** ڳʱжʵ
*/
typedef struct AVInputFormat
{
	// ļ
    const char *name;

    int priv_data_size;

	// ̽⺯
    int(*read_probe)(AVProbeData*);

	// ȡͷ
    int(*read_header)(struct AVFormatContext *, AVFormatParameters *ap);

	// ȡһ֡ݣһݰ
    int(*read_packet)(struct AVFormatContext *, AVPacket *pkt);

	// رļ
    int(*read_close)(struct AVFormatContext*);

    const char *extensions;     // ļչ

	// һļĸʽ
    struct AVInputFormat *next;

} AVInputFormat;

/* 
** AVFormatContext ṹʾеĵǰļʽʹõģ 
** ļеԣкһʵ
*/
typedef struct AVFormatContext  // format I/O context
{
	// ļĸʽAVFormatContextһĸAVInputFormatһĸ
    struct AVInputFormat *iformat; 

    void *priv_data;

	// ļ
    ByteIOContext pb;

	// 
    int nb_streams;

	// ƵƵ
    AVStream *streams[MAX_STREAMS];

} AVFormatContext;

int avidec_init(void);

void av_register_input_format(AVInputFormat *format);

void av_register_all(void);

AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened);
int match_ext(const char *filename, const char *extensions);

int av_open_input_stream(AVFormatContext **ic_ptr, ByteIOContext *pb, const char *filename, 
						 AVInputFormat *fmt, AVFormatParameters *ap);

int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, 
					   int buf_size, AVFormatParameters *ap);

int av_read_frame(AVFormatContext *s, AVPacket *pkt);
int av_read_packet(AVFormatContext *s, AVPacket *pkt);
void av_close_input_file(AVFormatContext *s);
AVStream *av_new_stream(AVFormatContext *s, int id);
void av_set_pts_info(AVStream *s, int pts_wrap_bits, int pts_num, int pts_den);

int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags);
int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, int size, int distance, int flags);

int strstart(const char *str, const char *val, const char **ptr);
void pstrcpy(char *buf, int buf_size, const char *str);

#ifdef __cplusplus
}

#endif

#endif
