diff --git a/cmdutils.c b/cmdutils.c
index 9f58b14..8e0f73e 100644
--- a/cmdutils.c
+++ b/cmdutils.c
@@ -1337,84 +1337,6 @@ int show_devices(void *optctx, const char *opt, const char *arg)
         printf("\n");                                                        \
     }                                                                        \
 
-static void print_codec(const AVCodec *c)
-{
-    int encoder = av_codec_is_encoder(c);
-
-    printf("%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name,
-           c->long_name ? c->long_name : "");
-
-    printf("    General capabilities: ");
-    if (c->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)
-        printf("horizband ");
-    if (c->capabilities & AV_CODEC_CAP_DR1)
-        printf("dr1 ");
-    if (c->capabilities & AV_CODEC_CAP_TRUNCATED)
-        printf("trunc ");
-    if (c->capabilities & AV_CODEC_CAP_DELAY)
-        printf("delay ");
-    if (c->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME)
-        printf("small ");
-    if (c->capabilities & AV_CODEC_CAP_SUBFRAMES)
-        printf("subframes ");
-    if (c->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
-        printf("exp ");
-    if (c->capabilities & AV_CODEC_CAP_CHANNEL_CONF)
-        printf("chconf ");
-    if (c->capabilities & AV_CODEC_CAP_PARAM_CHANGE)
-        printf("paramchange ");
-    if (c->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
-        printf("variable ");
-    if (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
-                           AV_CODEC_CAP_SLICE_THREADS |
-                           AV_CODEC_CAP_AUTO_THREADS))
-        printf("threads ");
-    if (!c->capabilities)
-        printf("none");
-    printf("\n");
-
-    if (c->type == AVMEDIA_TYPE_VIDEO ||
-        c->type == AVMEDIA_TYPE_AUDIO) {
-        printf("    Threading capabilities: ");
-        switch (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
-                                   AV_CODEC_CAP_SLICE_THREADS |
-                                   AV_CODEC_CAP_AUTO_THREADS)) {
-        case AV_CODEC_CAP_FRAME_THREADS |
-             AV_CODEC_CAP_SLICE_THREADS: printf("frame and slice"); break;
-        case AV_CODEC_CAP_FRAME_THREADS: printf("frame");           break;
-        case AV_CODEC_CAP_SLICE_THREADS: printf("slice");           break;
-        case AV_CODEC_CAP_AUTO_THREADS : printf("auto");            break;
-        default:                         printf("none");            break;
-        }
-        printf("\n");
-    }
-
-    if (c->supported_framerates) {
-        const AVRational *fps = c->supported_framerates;
-
-        printf("    Supported framerates:");
-        while (fps->num) {
-            printf(" %d/%d", fps->num, fps->den);
-            fps++;
-        }
-        printf("\n");
-    }
-    PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, "pixel formats",
-                          AV_PIX_FMT_NONE, GET_PIX_FMT_NAME);
-    PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, "sample rates", 0,
-                          GET_SAMPLE_RATE_NAME);
-    PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats",
-                          AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME);
-    PRINT_CODEC_SUPPORTED(c, channel_layouts, uint64_t, "channel layouts",
-                          0, GET_CH_LAYOUT_DESC);
-
-    if (c->priv_class) {
-        av_show_help_children(c->priv_class,
-                           AV_OPT_FLAG_ENCODING_PARAM |
-                           AV_OPT_FLAG_DECODING_PARAM);
-    }
-}
-
 static char get_media_type_char(enum AVMediaType type)
 {
     switch (type) {
@@ -1427,176 +1349,6 @@ static char get_media_type_char(enum AVMediaType type)
     }
 }
 
-static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev,
-                                        int encoder)
-{
-    while ((prev = av_codec_next(prev))) {
-        if (prev->id == id &&
-            (encoder ? av_codec_is_encoder(prev) : av_codec_is_decoder(prev)))
-            return prev;
-    }
-    return NULL;
-}
-
-static int compare_codec_desc(const void *a, const void *b)
-{
-    const AVCodecDescriptor * const *da = a;
-    const AVCodecDescriptor * const *db = b;
-
-    return (*da)->type != (*db)->type ? FFDIFFSIGN((*da)->type, (*db)->type) :
-           strcmp((*da)->name, (*db)->name);
-}
-
-static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs)
-{
-    const AVCodecDescriptor *desc = NULL;
-    const AVCodecDescriptor **codecs;
-    unsigned nb_codecs = 0, i = 0;
-
-    while ((desc = avcodec_descriptor_next(desc)))
-        nb_codecs++;
-    if (!(codecs = av_calloc(nb_codecs, sizeof(*codecs)))) {
-        av_log(NULL, AV_LOG_ERROR, "Out of memory\n");
-        exit_program(1);
-    }
-    desc = NULL;
-    while ((desc = avcodec_descriptor_next(desc)))
-        codecs[i++] = desc;
-    av_assert0(i == nb_codecs);
-    qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc);
-    *rcodecs = codecs;
-    return nb_codecs;
-}
-
-static void print_codecs_for_id(enum AVCodecID id, int encoder)
-{
-    const AVCodec *codec = NULL;
-
-    printf(" (%s: ", encoder ? "encoders" : "decoders");
-
-    while ((codec = next_codec_for_id(id, codec, encoder)))
-        printf("%s ", codec->name);
-
-    printf(")");
-}
-
-int show_codecs(void *optctx, const char *opt, const char *arg)
-{
-    const AVCodecDescriptor **codecs;
-    unsigned i, nb_codecs = get_codecs_sorted(&codecs);
-
-    printf("Codecs:\n"
-           " D..... = Decoding supported\n"
-           " .E.... = Encoding supported\n"
-           " ..V... = Video codec\n"
-           " ..A... = Audio codec\n"
-           " ..S... = Subtitle codec\n"
-           " ...I.. = Intra frame-only codec\n"
-           " ....L. = Lossy compression\n"
-           " .....S = Lossless compression\n"
-           " -------\n");
-    for (i = 0; i < nb_codecs; i++) {
-        const AVCodecDescriptor *desc = codecs[i];
-        const AVCodec *codec = NULL;
-
-        if (strstr(desc->name, "_deprecated"))
-            continue;
-
-        printf(" ");
-        printf(avcodec_find_decoder(desc->id) ? "D" : ".");
-        printf(avcodec_find_encoder(desc->id) ? "E" : ".");
-
-        printf("%c", get_media_type_char(desc->type));
-        printf((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : ".");
-        printf((desc->props & AV_CODEC_PROP_LOSSY)      ? "L" : ".");
-        printf((desc->props & AV_CODEC_PROP_LOSSLESS)   ? "S" : ".");
-
-        printf(" %-20s %s", desc->name, desc->long_name ? desc->long_name : "");
-
-        /* print decoders/encoders when there's more than one or their
-         * names are different from codec name */
-        while ((codec = next_codec_for_id(desc->id, codec, 0))) {
-            if (strcmp(codec->name, desc->name)) {
-                print_codecs_for_id(desc->id, 0);
-                break;
-            }
-        }
-        codec = NULL;
-        while ((codec = next_codec_for_id(desc->id, codec, 1))) {
-            if (strcmp(codec->name, desc->name)) {
-                print_codecs_for_id(desc->id, 1);
-                break;
-            }
-        }
-
-        printf("\n");
-    }
-    av_free(codecs);
-    return 0;
-}
-
-static void print_codecs(int encoder)
-{
-    const AVCodecDescriptor **codecs;
-    unsigned i, nb_codecs = get_codecs_sorted(&codecs);
-
-    printf("%s:\n"
-           " V..... = Video\n"
-           " A..... = Audio\n"
-           " S..... = Subtitle\n"
-           " .F.... = Frame-level multithreading\n"
-           " ..S... = Slice-level multithreading\n"
-           " ...X.. = Codec is experimental\n"
-           " ....B. = Supports draw_horiz_band\n"
-           " .....D = Supports direct rendering method 1\n"
-           " ------\n",
-           encoder ? "Encoders" : "Decoders");
-    for (i = 0; i < nb_codecs; i++) {
-        const AVCodecDescriptor *desc = codecs[i];
-        const AVCodec *codec = NULL;
-
-        while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
-            printf(" %c", get_media_type_char(desc->type));
-            printf((codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) ? "F" : ".");
-            printf((codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) ? "S" : ".");
-            printf((codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL)  ? "X" : ".");
-            printf((codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)?"B" : ".");
-            printf((codec->capabilities & AV_CODEC_CAP_DR1)           ? "D" : ".");
-
-            printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : "");
-            if (strcmp(codec->name, desc->name))
-                printf(" (codec %s)", desc->name);
-
-            printf("\n");
-        }
-    }
-    av_free(codecs);
-}
-
-int show_decoders(void *optctx, const char *opt, const char *arg)
-{
-    print_codecs(0);
-    return 0;
-}
-
-int show_encoders(void *optctx, const char *opt, const char *arg)
-{
-    print_codecs(1);
-    return 0;
-}
-
-int show_bsfs(void *optctx, const char *opt, const char *arg)
-{
-    const AVBitStreamFilter *bsf = NULL;
-    void *opaque = NULL;
-
-    printf("Bitstream filters:\n");
-    while ((bsf = av_bsf_next(&opaque)))
-        printf("%s\n", bsf->name);
-    printf("\n");
-    return 0;
-}
-
 int show_protocols(void *optctx, const char *opt, const char *arg)
 {
     void *opaque = NULL;
@@ -1743,41 +1495,6 @@ int show_sample_fmts(void *optctx, const char *opt, const char *arg)
     return 0;
 }
 
-static void show_help_codec(const char *name, int encoder)
-{
-    const AVCodecDescriptor *desc;
-    const AVCodec *codec;
-
-    if (!name) {
-        av_log(NULL, AV_LOG_ERROR, "No codec name specified.\n");
-        return;
-    }
-
-    codec = encoder ? avcodec_find_encoder_by_name(name) :
-                      avcodec_find_decoder_by_name(name);
-
-    if (codec)
-        print_codec(codec);
-    else if ((desc = avcodec_descriptor_get_by_name(name))) {
-        int printed = 0;
-
-        while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
-            printed = 1;
-            print_codec(codec);
-        }
-
-        if (!printed) {
-            av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to FFmpeg, "
-                   "but no %s for it are available. FFmpeg might need to be "
-                   "recompiled with additional external libraries.\n",
-                   name, encoder ? "encoders" : "decoders");
-        }
-    } else {
-        av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by FFmpeg.\n",
-               name);
-    }
-}
-
 static void show_help_demuxer(const char *name)
 {
     const AVInputFormat *fmt = av_find_input_format(name);
@@ -1900,9 +1617,9 @@ int show_help(void *optctx, const char *opt, const char *arg)
     if (!*topic) {
         show_help_default(topic, par);
     } else if (!strcmp(topic, "decoder")) {
-        show_help_codec(par, 0);
+        av_show_help_codec(par, 0);
     } else if (!strcmp(topic, "encoder")) {
-        show_help_codec(par, 1);
+        av_show_help_codec(par, 1);
     } else if (!strcmp(topic, "demuxer")) {
         show_help_demuxer(par);
     } else if (!strcmp(topic, "muxer")) {
diff --git a/cmdutils.h b/cmdutils.h
index 38589cd..1ffee32 100644
--- a/cmdutils.h
+++ b/cmdutils.h
@@ -472,25 +472,6 @@ int show_sources(void *optctx, const char *opt, const char *arg);
 #endif
 
 /**
- * Print a listing containing all the codecs supported by the
- * program.
- * This option processing function does not utilize the arguments.
- */
-int show_codecs(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the decoders supported by the
- * program.
- */
-int show_decoders(void *optctx, const char *opt, const char *arg);
-
-/**
- * Print a listing containing all the encoders supported by the
- * program.
- */
-int show_encoders(void *optctx, const char *opt, const char *arg);
-
-/**
  * Print a listing containing all the filters supported by the
  * program.
  * This option processing function does not utilize the arguments.
@@ -498,13 +479,6 @@ int show_encoders(void *optctx, const char *opt, const char *arg);
 int show_filters(void *optctx, const char *opt, const char *arg);
 
 /**
- * Print a listing containing all the bit stream filters supported by the
- * program.
- * This option processing function does not utilize the arguments.
- */
-int show_bsfs(void *optctx, const char *opt, const char *arg);
-
-/**
  * Print a listing containing all the protocols supported by the
  * program.
  * This option processing function does not utilize the arguments.
diff --git a/cmdutils_common_opts.h b/cmdutils_common_opts.h
index f7c1ca4..2f5574f 100644
--- a/cmdutils_common_opts.h
+++ b/cmdutils_common_opts.h
@@ -9,10 +9,10 @@
     { "muxers"     , OPT_EXIT, {.func_arg = show_muxers   },    "show available muxers" },
     { "demuxers"   , OPT_EXIT, {.func_arg = show_demuxers },    "show available demuxers" },
     { "devices"    , OPT_EXIT, {.func_arg = show_devices  },    "show available devices" },
-    { "codecs"     , OPT_EXIT, {.func_arg = show_codecs   },    "show available codecs" },
-    { "decoders"   , OPT_EXIT, {.func_arg = show_decoders },    "show available decoders" },
-    { "encoders"   , OPT_EXIT, {.func_arg = show_encoders },    "show available encoders" },
-    { "bsfs"       , OPT_EXIT, {.func_arg = show_bsfs     },    "show available bit stream filters" },
+    { "codecs"     , OPT_EXIT, {.func_arg = av_show_codecs   }, "show available codecs" },
+    { "decoders"   , OPT_EXIT, {.func_arg = av_show_decoders }, "show available decoders" },
+    { "encoders"   , OPT_EXIT, {.func_arg = av_show_encoders }, "show available encoders" },
+    { "bsfs"       , OPT_EXIT, {.func_arg = av_show_bsfs  },    "show available bit stream filters" },
     { "protocols"  , OPT_EXIT, {.func_arg = show_protocols},    "show available protocols" },
     { "filters"    , OPT_EXIT, {.func_arg = show_filters  },    "show available filters" },
     { "pix_fmts"   , OPT_EXIT, {.func_arg = show_pix_fmts },    "show available pixel formats" },
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index f1d5bf1..08ca7fd 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -29,6 +29,7 @@ OBJS = allcodecs.o                                                      \
        bitstream_filter.o                                               \
        bitstream_filters.o                                              \
        bsf.o                                                            \
+       cmdutils.o                                                       \
        codec_desc.o                                                     \
        d3d11va.o                                                        \
        dirac.o                                                          \
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 211112f..0cfe6ce 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -6234,6 +6234,34 @@ const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name);
 AVCPBProperties *av_cpb_properties_alloc(size_t *size);
 
 /**
+ * Print a listing containing all the codecs supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int av_show_codecs(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the decoders supported by the
+ * program.
+ */
+int av_show_decoders(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the encoders supported by the
+ * program.
+ */
+int av_show_encoders(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing all the bit stream filters supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int av_show_bsfs(void *optctx, const char *opt, const char *arg);
+
+void av_show_help_codec(const char *name, int encoder);
+
+/**
  * @}
  */
 
diff --git a/libavcodec/cmdutils.c b/libavcodec/cmdutils.c
new file mode 100644
index 0000000..c22ce8c
--- /dev/null
+++ b/libavcodec/cmdutils.c
@@ -0,0 +1,383 @@
+/*
+ * Various utilities for command line tools
+ * Copyright (c) 2000-2003 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <math.h>
+
+/* Include only the enabled headers since some compilers (namely, Sun
+   Studio) will not omit unused inline functions and create undefined
+   references to libraries that are not being built. */
+
+#include "config.h"
+#include "compat/va_copy.h"
+#include "libavformat/avformat.h"
+#include "libavfilter/avfilter.h"
+#include "libavdevice/avdevice.h"
+#include "libavresample/avresample.h"
+#include "libswscale/swscale.h"
+#include "libswresample/swresample.h"
+#include "libpostproc/postprocess.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/display.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/libm.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/eval.h"
+#include "libavutil/dict.h"
+#include "libavutil/opt.h"
+#include "libavutil/cpu.h"
+#include "libavutil/ffversion.h"
+#include "libavutil/version.h"
+
+
+#define GET_PIX_FMT_NAME(pix_fmt)\
+    const char *name = av_get_pix_fmt_name(pix_fmt);
+
+#define GET_SAMPLE_FMT_NAME(sample_fmt)\
+    const char *name = av_get_sample_fmt_name(sample_fmt)
+
+#define GET_SAMPLE_RATE_NAME(rate)\
+    char name[16];\
+    snprintf(name, sizeof(name), "%d", rate);
+
+#define GET_CH_LAYOUT_DESC(ch_layout)\
+    char name[128];\
+    av_get_channel_layout_string(name, sizeof(name), 0, ch_layout);
+
+#define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \
+    if (codec->field) {                                                      \
+        const type *p = codec->field;                                        \
+                                                                             \
+        printf("    Supported " list_name ":");                              \
+        while (*p != term) {                                                 \
+            get_name(*p);                                                    \
+            printf(" %s", name);                                             \
+            p++;                                                             \
+        }                                                                    \
+        printf("\n");                                                        \
+    }                                                                        \
+
+static void print_codec(const AVCodec *c)
+{
+    int encoder = av_codec_is_encoder(c);
+
+    printf("%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name,
+           c->long_name ? c->long_name : "");
+
+    printf("    General capabilities: ");
+    if (c->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)
+        printf("horizband ");
+    if (c->capabilities & AV_CODEC_CAP_DR1)
+        printf("dr1 ");
+    if (c->capabilities & AV_CODEC_CAP_TRUNCATED)
+        printf("trunc ");
+    if (c->capabilities & AV_CODEC_CAP_DELAY)
+        printf("delay ");
+    if (c->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME)
+        printf("small ");
+    if (c->capabilities & AV_CODEC_CAP_SUBFRAMES)
+        printf("subframes ");
+    if (c->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
+        printf("exp ");
+    if (c->capabilities & AV_CODEC_CAP_CHANNEL_CONF)
+        printf("chconf ");
+    if (c->capabilities & AV_CODEC_CAP_PARAM_CHANGE)
+        printf("paramchange ");
+    if (c->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
+        printf("variable ");
+    if (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
+                           AV_CODEC_CAP_SLICE_THREADS |
+                           AV_CODEC_CAP_AUTO_THREADS))
+        printf("threads ");
+    if (!c->capabilities)
+        printf("none");
+    printf("\n");
+
+    if (c->type == AVMEDIA_TYPE_VIDEO ||
+        c->type == AVMEDIA_TYPE_AUDIO) {
+        printf("    Threading capabilities: ");
+        switch (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
+                                   AV_CODEC_CAP_SLICE_THREADS |
+                                   AV_CODEC_CAP_AUTO_THREADS)) {
+        case AV_CODEC_CAP_FRAME_THREADS |
+             AV_CODEC_CAP_SLICE_THREADS: printf("frame and slice"); break;
+        case AV_CODEC_CAP_FRAME_THREADS: printf("frame");           break;
+        case AV_CODEC_CAP_SLICE_THREADS: printf("slice");           break;
+        case AV_CODEC_CAP_AUTO_THREADS : printf("auto");            break;
+        default:                         printf("none");            break;
+        }
+        printf("\n");
+    }
+
+    if (c->supported_framerates) {
+        const AVRational *fps = c->supported_framerates;
+
+        printf("    Supported framerates:");
+        while (fps->num) {
+            printf(" %d/%d", fps->num, fps->den);
+            fps++;
+        }
+        printf("\n");
+    }
+    PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, "pixel formats",
+                          AV_PIX_FMT_NONE, GET_PIX_FMT_NAME);
+    PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, "sample rates", 0,
+                          GET_SAMPLE_RATE_NAME);
+    PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats",
+                          AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME);
+    PRINT_CODEC_SUPPORTED(c, channel_layouts, uint64_t, "channel layouts",
+                          0, GET_CH_LAYOUT_DESC);
+
+    if (c->priv_class) {
+        av_show_help_children(c->priv_class,
+                              AV_OPT_FLAG_ENCODING_PARAM |
+                              AV_OPT_FLAG_DECODING_PARAM);
+    }
+}
+
+static char get_media_type_char(enum AVMediaType type)
+{
+    switch (type) {
+        case AVMEDIA_TYPE_VIDEO:    return 'V';
+        case AVMEDIA_TYPE_AUDIO:    return 'A';
+        case AVMEDIA_TYPE_DATA:     return 'D';
+        case AVMEDIA_TYPE_SUBTITLE: return 'S';
+        case AVMEDIA_TYPE_ATTACHMENT:return 'T';
+        default:                    return '?';
+    }
+}
+
+static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev,
+                                        int encoder)
+{
+    while ((prev = av_codec_next(prev))) {
+        if (prev->id == id &&
+            (encoder ? av_codec_is_encoder(prev) : av_codec_is_decoder(prev)))
+            return prev;
+    }
+    return NULL;
+}
+
+static int compare_codec_desc(const void *a, const void *b)
+{
+    const AVCodecDescriptor * const *da = a;
+    const AVCodecDescriptor * const *db = b;
+
+    return (*da)->type != (*db)->type ? FFDIFFSIGN((*da)->type, (*db)->type) :
+           strcmp((*da)->name, (*db)->name);
+}
+
+static int get_codecs_sorted(const AVCodecDescriptor ***rcodecs)
+{
+    const AVCodecDescriptor *desc = NULL;
+    const AVCodecDescriptor **codecs;
+    unsigned nb_codecs = 0, i = 0;
+
+    while ((desc = avcodec_descriptor_next(desc)))
+        nb_codecs++;
+    if (!(codecs = av_calloc(nb_codecs, sizeof(*codecs)))) {
+        av_log(NULL, AV_LOG_ERROR, "Out of memory\n");
+        return AVERROR(ENOMEM);
+    }
+    desc = NULL;
+    while ((desc = avcodec_descriptor_next(desc)))
+        codecs[i++] = desc;
+    av_assert0(i == nb_codecs);
+    qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc);
+    *rcodecs = codecs;
+    return nb_codecs;
+}
+
+static void print_codecs_for_id(enum AVCodecID id, int encoder)
+{
+    const AVCodec *codec = NULL;
+
+    printf(" (%s: ", encoder ? "encoders" : "decoders");
+
+    while ((codec = next_codec_for_id(id, codec, encoder)))
+        printf("%s ", codec->name);
+
+    printf(")");
+}
+
+int av_show_codecs(void *optctx, const char *opt, const char *arg)
+{
+    const AVCodecDescriptor **codecs;
+    unsigned i;
+    int nb_codecs = get_codecs_sorted(&codecs);
+    if (nb_codecs < 0)
+        return nb_codecs;
+
+    printf("Codecs:\n"
+           " D..... = Decoding supported\n"
+           " .E.... = Encoding supported\n"
+           " ..V... = Video codec\n"
+           " ..A... = Audio codec\n"
+           " ..S... = Subtitle codec\n"
+           " ...I.. = Intra frame-only codec\n"
+           " ....L. = Lossy compression\n"
+           " .....S = Lossless compression\n"
+           " -------\n");
+    for (i = 0; i < nb_codecs; i++) {
+        const AVCodecDescriptor *desc = codecs[i];
+        const AVCodec *codec = NULL;
+
+        if (strstr(desc->name, "_deprecated"))
+            continue;
+
+        printf(" ");
+        printf(avcodec_find_decoder(desc->id) ? "D" : ".");
+        printf(avcodec_find_encoder(desc->id) ? "E" : ".");
+
+        printf("%c", get_media_type_char(desc->type));
+        printf((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : ".");
+        printf((desc->props & AV_CODEC_PROP_LOSSY)      ? "L" : ".");
+        printf((desc->props & AV_CODEC_PROP_LOSSLESS)   ? "S" : ".");
+
+        printf(" %-20s %s", desc->name, desc->long_name ? desc->long_name : "");
+
+        /* print decoders/encoders when there's more than one or their
+         * names are different from codec name */
+        while ((codec = next_codec_for_id(desc->id, codec, 0))) {
+            if (strcmp(codec->name, desc->name)) {
+                print_codecs_for_id(desc->id, 0);
+                break;
+            }
+        }
+        codec = NULL;
+        while ((codec = next_codec_for_id(desc->id, codec, 1))) {
+            if (strcmp(codec->name, desc->name)) {
+                print_codecs_for_id(desc->id, 1);
+                break;
+            }
+        }
+
+        printf("\n");
+    }
+    av_free(codecs);
+    return 0;
+}
+
+static int print_codecs(int encoder)
+{
+    const AVCodecDescriptor **codecs;
+    unsigned i;
+    int nb_codecs = get_codecs_sorted(&codecs);
+    if (nb_codecs < 0)
+        return nb_codecs;
+
+    printf("%s:\n"
+           " V..... = Video\n"
+           " A..... = Audio\n"
+           " S..... = Subtitle\n"
+           " .F.... = Frame-level multithreading\n"
+           " ..S... = Slice-level multithreading\n"
+           " ...X.. = Codec is experimental\n"
+           " ....B. = Supports draw_horiz_band\n"
+           " .....D = Supports direct rendering method 1\n"
+           " ------\n",
+           encoder ? "Encoders" : "Decoders");
+    for (i = 0; i < nb_codecs; i++) {
+        const AVCodecDescriptor *desc = codecs[i];
+        const AVCodec *codec = NULL;
+
+        while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
+            printf(" %c", get_media_type_char(desc->type));
+            printf((codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) ? "F" : ".");
+            printf((codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) ? "S" : ".");
+            printf((codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL)  ? "X" : ".");
+            printf((codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)?"B" : ".");
+            printf((codec->capabilities & AV_CODEC_CAP_DR1)           ? "D" : ".");
+
+            printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : "");
+            if (strcmp(codec->name, desc->name))
+                printf(" (codec %s)", desc->name);
+
+            printf("\n");
+        }
+    }
+    av_free(codecs);
+    return 0;
+}
+
+int av_show_decoders(void *optctx, const char *opt, const char *arg)
+{
+    return print_codecs(0);
+}
+
+int av_show_encoders(void *optctx, const char *opt, const char *arg)
+{
+    return print_codecs(1);
+}
+
+int av_show_bsfs(void *optctx, const char *opt, const char *arg)
+{
+    const AVBitStreamFilter *bsf = NULL;
+    void *opaque = NULL;
+
+    printf("Bitstream filters:\n");
+    while ((bsf = av_bsf_next(&opaque)))
+        printf("%s\n", bsf->name);
+    printf("\n");
+    return 0;
+}
+
+void av_show_help_codec(const char *name, int encoder)
+{
+    const AVCodecDescriptor *desc;
+    const AVCodec *codec;
+
+    if (!name) {
+        av_log(NULL, AV_LOG_ERROR, "No codec name specified.\n");
+        return;
+    }
+
+    codec = encoder ? avcodec_find_encoder_by_name(name) :
+                      avcodec_find_decoder_by_name(name);
+
+    if (codec)
+        print_codec(codec);
+    else if ((desc = avcodec_descriptor_get_by_name(name))) {
+        int printed = 0;
+
+        while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
+            printed = 1;
+            print_codec(codec);
+        }
+
+        if (!printed) {
+            av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to FFmpeg, "
+                   "but no %s for it are available. FFmpeg might need to be "
+                   "recompiled with additional external libraries.\n",
+                   name, encoder ? "encoders" : "decoders");
+        }
+    } else {
+        av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by FFmpeg.\n",
+               name);
+    }
+}
