#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/avstring.h>
#define SEEK_TYPE_TIME 0
#define SEEK_TYPE_BYTE 1
#define SEEK_TYPE_FRAME 2
#define SEEK_TARGET_FROM 0
#define SEEK_TARGET_UP_TO 1
#define SEEK_TARGET_PRECISE 2
AVInputFormat* ffw_guess_input_format(
const char* short_name,
const char* file_name,
const char* mime_type) {
const AVInputFormat* fmt = NULL;
const AVInputFormat* res = NULL;
void* i = NULL;
int score;
int max_score = 0;
while ((fmt = av_demuxer_iterate(&i))) {
score = 0;
if (short_name && fmt->name && av_match_name(short_name, fmt->name)) {
score += 100;
}
if (mime_type && fmt->mime_type && av_match_name(mime_type, fmt->mime_type)) {
score += 10;
}
if (file_name && fmt->extensions && av_match_ext(file_name, fmt->extensions)) {
score += 5;
}
if (score > max_score) {
max_score = score;
res = fmt;
}
}
return (AVInputFormat*)res;
}
const char* ffw_input_format_name(const AVInputFormat* input_format) {
return input_format->name;
}
typedef struct Demuxer {
AVFormatContext* fc;
AVDictionary* options;
AVPacket* packet;
} Demuxer;
Demuxer* ffw_demuxer_new();
int ffw_demuxer_init(Demuxer* demuxer, AVIOContext* io_context, AVInputFormat* format);
int ffw_demuxer_set_initial_option(Demuxer* demuxer, const char* key, const char* value);
int ffw_demuxer_set_option(Demuxer* demuxer, const char* key, const char* value);
int ffw_demuxer_find_stream_info(Demuxer* demuxer, int64_t max_analyze_duration);
unsigned ffw_demuxer_get_nb_streams(const Demuxer* demuxer);
AVStream* ffw_demuxer_get_stream(Demuxer* demuxer, unsigned stream_index);
const AVInputFormat* ffw_demuxer_get_input_format(const Demuxer* demuxer);
int ffw_demuxer_read_frame(Demuxer* demuxer, AVPacket** packet, int* tb_num, int* tb_den);
int ffw_demuxer_seek(Demuxer* demuxer, int64_t timestamp, int seek_by, int seek_target);
void ffw_demuxer_free(Demuxer* demuxer);
Demuxer* ffw_demuxer_new() {
Demuxer* demuxer = calloc(1, sizeof(Demuxer));
if (!demuxer) {
return NULL;
}
demuxer->packet = av_packet_alloc();
if (!demuxer->packet) {
goto err;
}
demuxer->fc = avformat_alloc_context();
if (!demuxer->fc) {
goto err;
}
return demuxer;
err:
ffw_demuxer_free(demuxer);
return NULL;
}
int ffw_demuxer_init(Demuxer* demuxer, AVIOContext* avio_context, AVInputFormat* format) {
int ret;
demuxer->fc->pb = avio_context;
ret = avformat_open_input(&demuxer->fc, NULL, format, &demuxer->options);
if (ret < 0) {
return ret;
}
av_dict_free(&demuxer->options);
return ret;
}
int ffw_demuxer_set_initial_option(Demuxer* demuxer, const char* key, const char* value) {
return av_dict_set(&demuxer->options, key, value, 0);
}
int ffw_demuxer_set_option(Demuxer* demuxer, const char* key, const char* value) {
return av_opt_set(demuxer->fc, key, value, AV_OPT_SEARCH_CHILDREN);
}
int ffw_demuxer_find_stream_info(Demuxer* demuxer, int64_t max_analyze_duration) {
AVRational micro;
AVRational dst;
micro.num = 1;
micro.den = 1000000;
dst.num = 1;
dst.den = AV_TIME_BASE;
max_analyze_duration = av_rescale_q(max_analyze_duration, micro, dst);
demuxer->fc->max_analyze_duration = max_analyze_duration;
return avformat_find_stream_info(demuxer->fc, NULL);
}
unsigned ffw_demuxer_get_nb_streams(const Demuxer* demuxer) {
return demuxer->fc->nb_streams;
}
AVStream* ffw_demuxer_get_stream(Demuxer* demuxer, unsigned stream_index) {
return demuxer->fc->streams[stream_index];
}
const AVInputFormat* ffw_demuxer_get_input_format(const Demuxer* demuxer) {
return demuxer->fc->iformat;
}
int ffw_demuxer_read_frame(Demuxer* demuxer, AVPacket** packet, int* tb_num, int* tb_den) {
AVStream* stream;
AVPacket* res;
int ret;
ret = av_read_frame(demuxer->fc, demuxer->packet);
if (ret == AVERROR_EOF) {
av_packet_unref(demuxer->packet);
*packet = NULL;
return 0;
} else if (ret < 0) {
av_packet_unref(demuxer->packet);
return ret;
}
res = av_packet_clone(demuxer->packet);
av_packet_unref(demuxer->packet);
if (!res) {
return AVERROR(ENOMEM);
}
stream = demuxer->fc->streams[res->stream_index];
*packet = res;
*tb_num = stream->time_base.num;
*tb_den = stream->time_base.den;
return ret;
}
int ffw_demuxer_seek(Demuxer* demuxer, int64_t timestamp, int seek_by, int seek_target) {
int flags;
flags = 0;
switch (seek_by) {
case SEEK_TYPE_BYTE:
flags |= AVSEEK_FLAG_BYTE;
break;
case SEEK_TYPE_FRAME:
flags |= AVSEEK_FLAG_FRAME;
break;
default:
break;
}
switch (seek_target) {
case SEEK_TARGET_UP_TO:
flags |= AVSEEK_FLAG_BACKWARD;
break;
case SEEK_TARGET_PRECISE:
flags |= AVSEEK_FLAG_ANY;
break;
default:
break;
}
return av_seek_frame(demuxer->fc, -1, timestamp, flags);
}
void ffw_demuxer_free(Demuxer* demuxer) {
if (!demuxer) {
return;
}
av_packet_free(&demuxer->packet);
avformat_close_input(&demuxer->fc);
av_dict_free(&demuxer->options);
free(demuxer);
}