ac-ffmpeg 0.15.2

Simple and safe Rust interface for FFmpeg libraries.
Documentation
#include <libavformat/avformat.h>
#include <libavutil/opt.h>

AVInputFormat* ffw_find_input_format(const char* short_name) {
    return av_find_input_format(short_name);
}

typedef struct Demuxer {
    AVFormatContext* fc;
    AVDictionary* options;
} 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);
AVCodecParameters* ffw_demuxer_get_codec_parameters(const Demuxer* demuxer, unsigned stream_index);
int ffw_demuxer_read_frame(Demuxer* demuxer, AVPacket** packet, uint32_t* tb_num, uint32_t* tb_den);
void ffw_demuxer_free(Demuxer* demuxer);

Demuxer* ffw_demuxer_new() {
    Demuxer* demuxer = calloc(1, sizeof(Demuxer));
    if (!demuxer) {
        return NULL;
    }

    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;
}

AVCodecParameters* ffw_demuxer_get_codec_parameters(const Demuxer* demuxer, unsigned stream_index) {
    AVCodecParameters* res;
    const AVStream* s;

    s = demuxer->fc->streams[stream_index];

    res = avcodec_parameters_alloc();
    if (!res) {
        return NULL;
    }

    if (avcodec_parameters_copy(res, s->codecpar) < 0) {
        goto err;
    }

    return res;

err:
    avcodec_parameters_free(&res);

    return NULL;
}

int ffw_demuxer_read_frame(Demuxer* demuxer, AVPacket** packet, uint32_t* tb_num, uint32_t* tb_den) {
    AVStream* stream;
    AVPacket* res;
    AVPacket tmp;
    int ret;

    av_init_packet(&tmp);

    ret = av_read_frame(demuxer->fc, &tmp);
    if (ret == AVERROR_EOF) {
        *packet = NULL;
        return 0;
    } else if (ret < 0) {
        return ret;
    }

    res = av_packet_clone(&tmp);

    av_packet_unref(&tmp);

    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;
}

void ffw_demuxer_free(Demuxer* demuxer) {
    if (!demuxer) {
        return;
    }

    avformat_close_input(&demuxer->fc);
    av_dict_free(&demuxer->options);

    free(demuxer);
}