From 0976126ebb60e6e7060c54872a363d165bc2b759 Mon Sep 17 00:00:00 2001 From: kc5nra Date: Sat, 28 Mar 2015 00:48:04 -0500 Subject: [PATCH] deps-libff: Add ff codec/format utility functions This adds utility functions for determining which codecs and formats are supported by loaded FFMpeg libraries. This includes validating the codecs that a particular format supports. --- deps/libff/CMakeLists.txt | 2 + deps/libff/libff/ff-util.c | 397 +++++++++++++++++++++++++++++++++++++ deps/libff/libff/ff-util.h | 69 +++++++ 3 files changed, 468 insertions(+) create mode 100644 deps/libff/libff/ff-util.c create mode 100644 deps/libff/libff/ff-util.h diff --git a/deps/libff/CMakeLists.txt b/deps/libff/CMakeLists.txt index 7a8d90571..37c6c5fb3 100644 --- a/deps/libff/CMakeLists.txt +++ b/deps/libff/CMakeLists.txt @@ -19,6 +19,7 @@ set(libff_HEADERS libff/ff-packet-queue.h libff/ff-threading.h libff/ff-timer.h + libff/ff-util.h # libff/ff-demuxer.h # @@ -30,6 +31,7 @@ set(libff_SOURCES libff/ff-clock.c libff/ff-packet-queue.c libff/ff-timer.c + libff/ff-util.c # libff/ff-demuxer.c # diff --git a/deps/libff/libff/ff-util.c b/deps/libff/libff/ff-util.c new file mode 100644 index 000000000..557e10d6b --- /dev/null +++ b/deps/libff/libff/ff-util.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2015 John R. Bradley + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ff-util.h" + +#include +#include +#include +#include + +#include + +struct ff_format_desc { + const char *name; + const char *long_name; + const char *mime_type; + enum AVCodecID audio_codec; + enum AVCodecID video_codec; + const struct AVCodecTag * const *codec_tags; + const struct ff_format_desc *next; +}; + +struct ff_codec_desc { + const char *name; + const char *long_name; + int id; + bool alias; + const char *base_name; + enum ff_codec_type type; + const struct ff_codec_desc *next; +}; + +void ff_init() +{ + av_register_all(); + avdevice_register_all(); + avcodec_register_all(); + avformat_network_init(); +} + +const char *ff_codec_name_from_id(int codec_id) +{ + AVCodec *codec = avcodec_find_encoder(codec_id); + if (codec != NULL) + return codec->name; + else + return NULL; +} + +static bool get_codecs(const AVCodecDescriptor*** descs, unsigned int *size) +{ + const AVCodecDescriptor *desc = NULL; + const AVCodecDescriptor **codecs; + unsigned int codec_count = 0; + unsigned int i = 0; + + while ((desc = avcodec_descriptor_next(desc))) + codec_count++; + + codecs = av_calloc(codec_count, sizeof(AVCodecDescriptor *)); + + if (codecs == NULL) { + av_log(NULL, AV_LOG_ERROR, "unable to allocate sorted codec " + "array with size %d", codec_count); + return false; + } + + while ((desc = avcodec_descriptor_next(desc))) + codecs[i++] = desc; + + *size = codec_count; + *descs = codecs; + return true; +} + +static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev) +{ + while ((prev = av_codec_next(prev))) { + if (prev->id == id && av_codec_is_encoder(prev)) + return prev; + } + + return NULL; +} + +static void add_codec_to_list(const struct ff_format_desc *format_desc, + struct ff_codec_desc **first, struct ff_codec_desc **current, + enum AVCodecID id, const AVCodec *codec) +{ + if (codec == NULL) + codec = avcodec_find_encoder(id); + + // No codec, or invalid id + if (codec == NULL) + return; + + // Not an encoding codec + if (!av_codec_is_encoder(codec)) + return; + + // Format doesn't support this codec + unsigned int tag = av_codec_get_tag(format_desc->codec_tags, + codec->id); + if (tag == 0) + return; + + struct ff_codec_desc *d = av_mallocz(sizeof(struct ff_codec_desc)); + + d->name = codec->name; + d->long_name = codec->long_name; + d->id = codec->id; + AVCodec *base_codec = avcodec_find_encoder(codec->id); + if (strcmp(base_codec->name, codec->name) != 0) { + d->alias = true; + d->base_name = base_codec->name; + } + + switch (codec->type) { + case AVMEDIA_TYPE_AUDIO: + d->type = FF_CODEC_AUDIO; + break; + case AVMEDIA_TYPE_VIDEO: + d->type = FF_CODEC_VIDEO; + break; + default: + d->type = FF_CODEC_UNKNOWN; + } + + if (*current != NULL) + (*current)->next = d; + else + *first = d; + + *current = d; +} + +static void get_codecs_for_id(const struct ff_format_desc *format_desc, + struct ff_codec_desc **first, struct ff_codec_desc **current, + enum AVCodecID id) +{ + const AVCodec *codec = NULL; + while ((codec = next_codec_for_id(id, codec))) + add_codec_to_list(format_desc, first, current, codec->id, + codec); +} + +const struct ff_codec_desc *ff_codec_supported( + const struct ff_format_desc *format_desc) +{ + const AVCodecDescriptor **codecs; + unsigned int size; + unsigned int i; + struct ff_codec_desc *current = NULL; + struct ff_codec_desc *first = NULL; + + if (!get_codecs(&codecs, &size)) + return NULL; + + for(i = 0; i < size; i++) { + const AVCodecDescriptor *codec = codecs[i]; + get_codecs_for_id(format_desc, &first, ¤t, codec->id); + } + + av_free((void *)codecs); + + return first; +} + +const char *ff_codec_desc_name(const struct ff_codec_desc *codec_desc) +{ + if (codec_desc != NULL) + return codec_desc->name; + else + return NULL; +} + +const char *ff_codec_desc_long_name(const struct ff_codec_desc *codec_desc) +{ + if (codec_desc != NULL) + return codec_desc->long_name; + else + return NULL; +} + +bool ff_codec_desc_is_alias(const struct ff_codec_desc *codec_desc) +{ + if (codec_desc != NULL) + return codec_desc->alias; + else + return false; +} + +const char *ff_codec_desc_base_name(const struct ff_codec_desc *codec_desc) +{ + if (codec_desc != NULL) + return codec_desc->base_name; + else + return NULL; +} + +enum ff_codec_type ff_codec_desc_type(const struct ff_codec_desc *codec_desc) +{ + if (codec_desc != NULL) + return codec_desc->type; + else + return FF_CODEC_UNKNOWN; +} + +const struct ff_codec_desc *ff_codec_desc_next( + const struct ff_codec_desc *codec_desc) +{ + if (codec_desc != NULL) + return codec_desc->next; + else + return NULL; +} + +int ff_codec_desc_id(const struct ff_codec_desc *codec_desc) +{ + if (codec_desc != NULL) + return codec_desc->id; + else + return AV_CODEC_ID_NONE; +} + +void ff_codec_desc_free(const struct ff_codec_desc *codec_desc) +{ + const struct ff_codec_desc *desc = codec_desc; + while(desc != NULL) { + const struct ff_codec_desc *next = desc->next; + av_free((void *)desc); + desc = next; + } +} + +static inline bool is_output_device(const AVClass *avclass) +{ + if (!avclass) + return 0; + + switch (avclass->category) { + case AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT: + case AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT: + case AV_CLASS_CATEGORY_DEVICE_OUTPUT: + return true; + default: + return false; + } +} + +const struct ff_format_desc *ff_format_supported() +{ + AVOutputFormat *output_format = NULL; + struct ff_format_desc *desc = NULL; + struct ff_format_desc *current = NULL; + + while ((output_format = av_oformat_next(output_format))) { + struct ff_format_desc *d; + if (is_output_device(output_format->priv_class)) + continue; + + d = av_mallocz(sizeof(struct ff_format_desc)); + + d->audio_codec = output_format->audio_codec; + d->video_codec = output_format->video_codec; + d->name = output_format->name; + d->long_name = output_format->long_name; + d->mime_type = output_format->mime_type; + d->codec_tags = output_format->codec_tag; + + if (current != NULL) { + current->next = d; + current = d; + } else { + desc = current = d; + } + } + + return desc; +} + +const char *ff_format_desc_name(const struct ff_format_desc *format_desc) +{ + if (format_desc != NULL) + return format_desc->name; + else + return NULL; +} + +const char *ff_format_desc_long_name(const struct ff_format_desc *format_desc) +{ + if (format_desc != NULL) + return format_desc->long_name; + else + return NULL; +} + +const char *ff_format_desc_mime_type(const struct ff_format_desc *format_desc) +{ + if (format_desc != NULL) + return format_desc->mime_type; + else + return NULL; +} + +bool ff_format_desc_has_audio(const struct ff_format_desc *format_desc) +{ + if (format_desc != NULL) + return format_desc->audio_codec != AV_CODEC_ID_NONE; + else + return false; +} + +bool ff_format_desc_has_video(const struct ff_format_desc *format_desc) +{ + if (format_desc != NULL) + return format_desc->video_codec != AV_CODEC_ID_NONE; + else + return false; +} + +int ff_format_desc_audio(const struct ff_format_desc *format_desc) +{ + if (format_desc != NULL) + return format_desc->audio_codec; + else + return false; +} + +int ff_format_desc_video(const struct ff_format_desc *format_desc) +{ + if (format_desc != NULL) + return format_desc->video_codec; + else + return false; +} + +const struct ff_format_desc *ff_format_desc_next( + const struct ff_format_desc *format_desc) +{ + if (format_desc != NULL) + return format_desc->next; + else + return NULL; +} + +static const char *get_encoder_name(const struct ff_format_desc *format_desc, + enum AVCodecID codec_id) +{ + AVCodec *codec = avcodec_find_encoder(codec_id); + if (codec == NULL && codec_id == AV_CODEC_ID_NONE) + return NULL; + else if (codec == NULL) + return format_desc->name; + else + return codec->name; +} + +const char *ff_format_desc_get_default_name( + const struct ff_format_desc *format_desc, + enum ff_codec_type codec_type) +{ + switch (codec_type) + { + case FF_CODEC_AUDIO: + return get_encoder_name(format_desc, + format_desc->audio_codec); + case FF_CODEC_VIDEO: + return get_encoder_name(format_desc, + format_desc->video_codec); + default: + return NULL; + } +} + +void ff_format_desc_free(const struct ff_format_desc *format_desc) +{ + const struct ff_format_desc *desc = format_desc; + while(desc != NULL) { + const struct ff_format_desc *next = desc->next; + av_free((void *)desc); + desc = next; + } +} diff --git a/deps/libff/libff/ff-util.h b/deps/libff/libff/ff-util.h new file mode 100644 index 000000000..d100eb6f5 --- /dev/null +++ b/deps/libff/libff/ff-util.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015 John R. Bradley + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum ff_codec_type { + FF_CODEC_AUDIO, + FF_CODEC_VIDEO, + FF_CODEC_UNKNOWN +}; + +struct ff_format_desc; +struct ff_codec_desc; + +void ff_init(); + +const char *ff_codec_name_from_id(int codec_id); + +// Codec Description +const struct ff_codec_desc *ff_codec_supported( + const struct ff_format_desc *format_desc); +void ff_codec_desc_free(const struct ff_codec_desc *codec_desc); +const char *ff_codec_desc_name(const struct ff_codec_desc *codec_desc); +const char *ff_codec_desc_long_name(const struct ff_codec_desc *codec_desc); +enum ff_codec_type ff_codec_desc_type(const struct ff_codec_desc *codec_desc); +bool ff_codec_desc_is_alias(const struct ff_codec_desc *codec_desc); +const char *ff_codec_desc_base_name(const struct ff_codec_desc *codec_desc); +int ff_codec_desc_id(const struct ff_codec_desc *codec_desc); +const struct ff_codec_desc *ff_codec_desc_next( + const struct ff_codec_desc *codec_desc); + +// Format Description +const struct ff_format_desc *ff_format_supported(); +void ff_format_desc_free(const struct ff_format_desc *format_desc); +const char *ff_format_desc_name(const struct ff_format_desc *format_desc); +const char *ff_format_desc_long_name(const struct ff_format_desc *format_desc); +const char *ff_format_desc_mime_type(const struct ff_format_desc *format_desc); +bool ff_format_desc_has_audio(const struct ff_format_desc *format_desc); +bool ff_format_desc_has_video(const struct ff_format_desc *format_desc); +int ff_format_desc_audio(const struct ff_format_desc *format_desc); +int ff_format_desc_video(const struct ff_format_desc *format_desc); +const char *ff_format_desc_get_default_name( + const struct ff_format_desc *format_desc, + enum ff_codec_type codec_type); +const struct ff_format_desc *ff_format_desc_next( + const struct ff_format_desc *format_desc); + +#ifdef __cplusplus +} +#endif