ffmpeg support on linux, and check compiled vs. runtime versions of ffmpeg
This commit is contained in:
+112
-14
@@ -31,6 +31,21 @@ extern "C" {
|
||||
#include <libswresample/swresample.h>
|
||||
}
|
||||
|
||||
#define MSG0(type, msg) fprintf(stderr, type ":");fprintf(stderr, "%s", __FUNCTION__);fprintf(stderr, ": %s\n", msg)
|
||||
#define MSG1(type, msg, a) fprintf(stderr, type ":");fprintf(stderr, "%s", __FUNCTION__);fprintf(stderr, ": " msg "\n", a)
|
||||
#define MSG2(type, msg, a, b) fprintf(stderr, type ":");fprintf(stderr, "%s", __FUNCTION__);fprintf(stderr, ": " msg "\n", a, b)
|
||||
#define MSG3(type, msg, a, b, c) fprintf(stderr, type ":");fprintf(stderr, "%s", __FUNCTION__);fprintf(stderr, ": " msg "\n", a, b, c)
|
||||
|
||||
#define INFO0(msg) MSG0("info", msg)
|
||||
#define INFO1(msg, a) MSG1("info", msg, a)
|
||||
#define INFO2(msg, a, b) MSG2("info", msg, a, b)
|
||||
#define INFO3(msg, a, b, c) MSG3("info", msg, a, b, c)
|
||||
|
||||
#define ERROR0(msg) MSG0("error", msg)
|
||||
#define ERROR1(msg, a) MSG1("error", msg, a)
|
||||
#define ERROR2(msg, a, b) MSG2("error", msg, a, b)
|
||||
#define ERROR3(msg, a, b, c) MSG3("error", msg, a, b, c)
|
||||
|
||||
static constexpr int FMPG_OUTPUT_BITS = 32;
|
||||
static constexpr int FMPG_OUTPUT_BYTES = 4;
|
||||
static constexpr AVSampleFormat FMPG_OUTPUT_FMT = AV_SAMPLE_FMT_S32;
|
||||
@@ -150,8 +165,11 @@ static const char *string_c_str(const std::string &s)
|
||||
}
|
||||
|
||||
static std::string get_metadata_string(const AVFormatContext *ctx,
|
||||
const char *key)
|
||||
const char *key, bool &has_metadata)
|
||||
{
|
||||
if (ctx->metadata == nullptr) { has_metadata = false; return ""; }
|
||||
|
||||
has_metadata = true;
|
||||
const AVDictionaryEntry *entry = av_dict_get(ctx->metadata,
|
||||
key,
|
||||
nullptr,
|
||||
@@ -160,8 +178,11 @@ static std::string get_metadata_string(const AVFormatContext *ctx,
|
||||
: std::string();
|
||||
}
|
||||
|
||||
static int get_metadata_int(const AVFormatContext *ctx, const char *key)
|
||||
static int get_metadata_int(const AVFormatContext *ctx, const char *key, bool &has_metadata)
|
||||
{
|
||||
if (ctx->metadata == nullptr) { has_metadata = false; return -1; }
|
||||
has_metadata = true;
|
||||
|
||||
const AVDictionaryEntry *entry = av_dict_get(ctx->metadata,
|
||||
key,
|
||||
nullptr,
|
||||
@@ -239,15 +260,17 @@ static void fill_file_metadata(fmpg_instance *self)
|
||||
{
|
||||
AVFormatContext *ctx = self->format_ctx;
|
||||
|
||||
bool has_metadata;
|
||||
|
||||
self->file_info.clear();
|
||||
self->file_info.title = get_metadata_string(ctx, "title");
|
||||
self->file_info.author = get_metadata_string(ctx, "artist");
|
||||
self->file_info.album = get_metadata_string(ctx, "album");
|
||||
self->file_info.genre = get_metadata_string(ctx, "genre");
|
||||
self->file_info.comment = get_metadata_string(ctx, "comment");
|
||||
self->file_info.copyright = get_metadata_string(ctx, "copyright");
|
||||
self->file_info.year = get_metadata_int(ctx, "year");
|
||||
self->file_info.track = get_metadata_int(ctx, "track");
|
||||
self->file_info.title = get_metadata_string(ctx, "title", has_metadata);
|
||||
self->file_info.author = get_metadata_string(ctx, "artist", has_metadata);
|
||||
self->file_info.album = get_metadata_string(ctx, "album", has_metadata);
|
||||
self->file_info.genre = get_metadata_string(ctx, "genre", has_metadata);
|
||||
self->file_info.comment = get_metadata_string(ctx, "comment", has_metadata);
|
||||
self->file_info.copyright = get_metadata_string(ctx, "copyright", has_metadata);
|
||||
self->file_info.year = get_metadata_int(ctx, "year", has_metadata);
|
||||
self->file_info.track = get_metadata_int(ctx, "track", has_metadata);
|
||||
self->file_info.bitrate = ctx->bit_rate > 0
|
||||
? static_cast<int>(ctx->bit_rate)
|
||||
: -1;
|
||||
@@ -360,8 +383,44 @@ static bool init_decoder(fmpg_instance *self)
|
||||
return init_codec_context(self) && init_resampler(self);
|
||||
}
|
||||
|
||||
int fmpg_compatible_ffmpeg()
|
||||
{
|
||||
int compiled_avformat_major = LIBAVFORMAT_VERSION_MAJOR;
|
||||
int compiled_avcodec_major = LIBAVCODEC_VERSION_MAJOR;
|
||||
int compiled_swresample_major = LIBSWRESAMPLE_VERSION_MAJOR;
|
||||
int compiled_avutil_major = LIBAVUTIL_VERSION_MAJOR;
|
||||
|
||||
int current_avformat_major = AV_VERSION_MAJOR(avformat_version());
|
||||
int current_avcodec_major = AV_VERSION_MAJOR(avcodec_version());
|
||||
int current_swresample_major = AV_VERSION_MAJOR(swresample_version());
|
||||
int current_avutil_major = AV_VERSION_MAJOR(avutil_version());
|
||||
|
||||
auto comp = [](const char *lib, int cv, int rv) {
|
||||
if (cv != rv) {
|
||||
ERROR3("FFMPEG %s Major versions not equal. Compile time: %d, runtime: %d", lib, cv, rv);
|
||||
}
|
||||
};
|
||||
|
||||
comp("AVFormat", compiled_avformat_major, current_avformat_major);
|
||||
comp("AVCodec", compiled_avcodec_major, current_avcodec_major);
|
||||
comp("SWResample", compiled_swresample_major, current_swresample_major);
|
||||
comp("AVUtil", compiled_avutil_major, current_avutil_major);
|
||||
|
||||
int compatible = (compiled_avformat_major == current_avformat_major) &&
|
||||
(compiled_avcodec_major == current_avcodec_major) &&
|
||||
(compiled_swresample_major == current_swresample_major) &&
|
||||
(compiled_avutil_major == current_avutil_major);
|
||||
|
||||
return compatible;
|
||||
}
|
||||
|
||||
fmpg_instance *fmpg_init(void)
|
||||
{
|
||||
if (!fmpg_compatible_ffmpeg()) {
|
||||
ERROR0("Compiled major ffmpeg version ≃ runtime major version, not compatible.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
return new fmpg_instance();
|
||||
} catch (...) {
|
||||
@@ -380,14 +439,21 @@ int fmpg_open_file(fmpg_instance *instance, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (avformat_open_input(&instance->format_ctx,
|
||||
filename,
|
||||
nullptr,
|
||||
nullptr) < 0) {
|
||||
if (instance->format_ctx != nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int r = avformat_open_input(&instance->format_ctx,
|
||||
filename,
|
||||
nullptr,
|
||||
nullptr);
|
||||
if (r < 0) {
|
||||
fmpg_close(instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "metadata: %p", instance->format_ctx->metadata);
|
||||
|
||||
if (avformat_find_stream_info(instance->format_ctx, nullptr) < 0) {
|
||||
fmpg_close(instance);
|
||||
return 0;
|
||||
@@ -923,3 +989,35 @@ double fmpg_timecode(fmpg_instance *instance)
|
||||
{
|
||||
return instance ? instance->decoder.timecode : 0.0;
|
||||
}
|
||||
|
||||
const char *fmpg_ffmpeg_version()
|
||||
{
|
||||
static char *version = nullptr;
|
||||
|
||||
if (version == nullptr) {
|
||||
version = static_cast<char *>(malloc(1024));
|
||||
}
|
||||
sprintf(version, "avformat: %u.%u.%u (%d), avcodec: %u.%u.%u (%d), swresample: %u.%u.%u (%d), avutil: %u.%u.%u (%d)",
|
||||
LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO, LIBAVFORMAT_VERSION_INT,
|
||||
LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO, LIBAVCODEC_VERSION_INT,
|
||||
LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO, LIBSWRESAMPLE_VERSION_INT,
|
||||
LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO, LIBAVUTIL_VERSION_INT
|
||||
);
|
||||
return version;
|
||||
}
|
||||
|
||||
const char *fmpg_int_version2string(int ver)
|
||||
{
|
||||
static char *version = nullptr;
|
||||
|
||||
if (version == nullptr) {
|
||||
version = static_cast<char *>(malloc(1024));
|
||||
}
|
||||
|
||||
int major = AV_VERSION_MAJOR(ver);
|
||||
int minor = AV_VERSION_MINOR(ver);
|
||||
int micro = AV_VERSION_MICRO(ver);
|
||||
sprintf(version, "%u.%u.%u", major, minor, micro);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user