diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 12d9b3d47c1e4cd6a9d0b51e59031f2b2e24b57e..251e47dbc62182798109e2946a99bb3ab64fa30f 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -3258,6 +3258,19 @@ AVCodecContext *avcodec_alloc_context(void);
  *  we WILL change its arguments and name a few times! */
 AVCodecContext *avcodec_alloc_context2(enum AVMediaType);
 
+/**
+ * Copy the settings of the source AVCodecContext into the destination
+ * AVCodecContext. The resulting destination codec context will be
+ * unopened, i.e. you are required to call avcodec_open() before you
+ * can use this AVCodecContext to decode/encode video/audio data.
+ *
+ * @param dest target codec context, should be initialized with
+ *             avcodec_alloc_context(), but otherwise uninitialized
+ * @param src source codec context
+ * @return AVERROR() on error (e.g. memory allocation error), 0 on success
+ */
+int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src);
+
 /**
  * Sets the fields of the given AVFrame to default values.
  *
diff --git a/libavcodec/options.c b/libavcodec/options.c
index 89b25483c219378610bdee7b59876244b2c507d8..04fd3ba496991f493beebcd5b1c713974c436e42 100644
--- a/libavcodec/options.c
+++ b/libavcodec/options.c
@@ -471,3 +471,63 @@ AVCodecContext *avcodec_alloc_context(void){
     return avcodec_alloc_context2(AVMEDIA_TYPE_UNKNOWN);
 }
 
+int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
+{
+    if (dest->codec) { // check that the dest context is uninitialized
+        av_log(dest, AV_LOG_ERROR,
+               "Tried to copy AVCodecContext %p into already-initialized %p\n",
+               src, dest);
+        return AVERROR(EINVAL);
+    }
+    memcpy(dest, src, sizeof(*dest));
+
+    /* set values specific to opened codecs back to their default state */
+    dest->priv_data       = NULL;
+    dest->codec           = NULL;
+    dest->palctrl         = NULL;
+    dest->slice_offset    = NULL;
+    dest->internal_buffer = NULL;
+    dest->hwaccel         = NULL;
+    dest->execute         = NULL;
+    dest->execute2        = NULL;
+    dest->reget_buffer    = NULL;
+    dest->thread_opaque   = NULL;
+
+    /* reallocate values that should be allocated separately */
+    dest->rc_eq           = NULL;
+    dest->extradata       = NULL;
+    dest->intra_matrix    = NULL;
+    dest->inter_matrix    = NULL;
+    dest->rc_override     = NULL;
+    if (src->rc_eq) {
+        dest->rc_eq = av_strdup(src->rc_eq);
+        if (!dest->rc_eq)
+            return AVERROR(ENOMEM);
+    }
+
+#define alloc_and_copy_or_fail(obj, size, pad) \
+    if (src->obj && size > 0) { \
+        dest->obj = av_malloc(size + pad); \
+        if (!dest->obj) \
+            goto fail; \
+        memcpy(dest->obj, src->obj, size); \
+        if (pad) \
+            memset(((uint8_t *) dest->obj) + size, 0, pad); \
+    }
+    alloc_and_copy_or_fail(extradata,    src->extradata_size,
+                           FF_INPUT_BUFFER_PADDING_SIZE);
+    alloc_and_copy_or_fail(intra_matrix, 64 * sizeof(int16_t), 0);
+    alloc_and_copy_or_fail(inter_matrix, 64 * sizeof(int16_t), 0);
+    alloc_and_copy_or_fail(rc_override,  src->rc_override_count * sizeof(*src->rc_override), 0);
+#undef alloc_and_copy_or_fail
+
+    return 0;
+
+fail:
+    av_freep(&dest->rc_override);
+    av_freep(&dest->intra_matrix);
+    av_freep(&dest->inter_matrix);
+    av_freep(&dest->extradata);
+    av_freep(&dest->rc_eq);
+    return AVERROR(ENOMEM);
+}