diff --git a/doc/APIchanges b/doc/APIchanges
index b9cdce6a28b44948f925c37574dd089af69fa1f6..f0bfffcc0e5cb1a5f54f50784dd9e14d57f0d569 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,9 @@ libavutil:     2015-08-28
 
 API changes, most recent first:
 
+2015-10-22 - xxxxxxx - lavc 57.8.100 / lavc 57.0.0 - qsv.h
+  Add an API for allocating opaque surfaces.
+
 2015-10-15 - xxxxxxx - lavf 57.4.100
   Remove the latm demuxer that was a duplicate of the loas demuxer.
 
diff --git a/libavcodec/qsv.h b/libavcodec/qsv.h
index 6049629cc94ffc53f528ca522919db6bd22e6909..b77158ec262920cfee3346de1f0f1cbce9157bfa 100644
--- a/libavcodec/qsv.h
+++ b/libavcodec/qsv.h
@@ -23,6 +23,8 @@
 
 #include <mfx/mfxvideo.h>
 
+#include "libavutil/buffer.h"
+
 /**
  * This struct is used for communicating QSV parameters between libavcodec and
  * the caller. It is managed by the caller and must be assigned to
@@ -48,6 +50,51 @@ typedef struct AVQSVContext {
      */
     mfxExtBuffer **ext_buffers;
     int         nb_ext_buffers;
+
+    /**
+     * Encoding only. If this field is set to non-zero by the caller, libavcodec
+     * will create an mfxExtOpaqueSurfaceAlloc extended buffer and pass it to
+     * the encoder initialization. This only makes sense if iopattern is also
+     * set to MFX_IOPATTERN_IN_OPAQUE_MEMORY.
+     *
+     * The number of allocated opaque surfaces will be the sum of the number
+     * required by the encoder and the user-provided value nb_opaque_surfaces.
+     * The array of the opaque surfaces will be exported to the caller through
+     * the opaque_surfaces field.
+     */
+    int opaque_alloc;
+
+    /**
+     * Encoding only, and only if opaque_alloc is set to non-zero. Before
+     * calling avcodec_open2(), the caller should set this field to the number
+     * of extra opaque surfaces to allocate beyond what is required by the
+     * encoder.
+     *
+     * On return from avcodec_open2(), this field will be set by libavcodec to
+     * the total number of allocated opaque surfaces.
+     */
+    int nb_opaque_surfaces;
+
+    /**
+     * Encoding only, and only if opaque_alloc is set to non-zero. On return
+     * from avcodec_open2(), this field will be used by libavcodec to export the
+     * array of the allocated opaque surfaces to the caller, so they can be
+     * passed to other parts of the pipeline.
+     *
+     * The buffer reference exported here is owned and managed by libavcodec,
+     * the callers should make their own reference with av_buffer_ref() and free
+     * it with av_buffer_unref() when it is no longer needed.
+     *
+     * The buffer data is an nb_opaque_surfaces-sized array of mfxFrameSurface1.
+     */
+    AVBufferRef *opaque_surfaces;
+
+    /**
+     * Encoding only, and only if opaque_alloc is set to non-zero. On return
+     * from avcodec_open2(), this field will be set to the surface type used in
+     * the opaque allocation request.
+     */
+    int opaque_alloc_type;
 } AVQSVContext;
 
 /**
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 08ff413ec46ae70a4f269797e97b20a1aa6378cd..df1f7778bd2e93e4142fd68cd77cf3b19927c339 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -160,7 +160,7 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
         q->extco.PicTimingSEI         = q->pic_timing_sei ?
                                         MFX_CODINGOPTION_ON : MFX_CODINGOPTION_UNKNOWN;
 
-        q->extparam_internal[0] = (mfxExtBuffer *)&q->extco;
+        q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco;
 
 #if QSV_VERSION_ATLEAST(1,6)
         q->extco2.Header.BufferId      = MFX_EXTBUFF_CODING_OPTION2;
@@ -175,7 +175,7 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
         q->extco2.LookAheadDS           = q->look_ahead_downsampling;
 #endif
 
-        q->extparam_internal[1] = (mfxExtBuffer *)&q->extco2;
+        q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2;
 
 #endif
     }
@@ -230,8 +230,46 @@ static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q)
     return 0;
 }
 
+static int qsv_init_opaque_alloc(AVCodecContext *avctx, QSVEncContext *q)
+{
+    AVQSVContext *qsv = avctx->hwaccel_context;
+    mfxFrameSurface1 *surfaces;
+    int nb_surfaces, i;
+
+    nb_surfaces = qsv->nb_opaque_surfaces + q->req.NumFrameSuggested + q->async_depth;
+
+    q->opaque_alloc_buf = av_buffer_allocz(sizeof(*surfaces) * nb_surfaces);
+    if (!q->opaque_alloc_buf)
+        return AVERROR(ENOMEM);
+
+    q->opaque_surfaces = av_malloc_array(nb_surfaces, sizeof(*q->opaque_surfaces));
+    if (!q->opaque_surfaces)
+        return AVERROR(ENOMEM);
+
+    surfaces = (mfxFrameSurface1*)q->opaque_alloc_buf->data;
+    for (i = 0; i < nb_surfaces; i++) {
+        surfaces[i].Info      = q->req.Info;
+        q->opaque_surfaces[i] = surfaces + i;
+    }
+
+    q->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
+    q->opaque_alloc.Header.BufferSz = sizeof(q->opaque_alloc);
+    q->opaque_alloc.In.Surfaces     = q->opaque_surfaces;
+    q->opaque_alloc.In.NumSurface   = nb_surfaces;
+    q->opaque_alloc.In.Type         = q->req.Type;
+
+    q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->opaque_alloc;
+
+    qsv->nb_opaque_surfaces = nb_surfaces;
+    qsv->opaque_surfaces    = q->opaque_alloc_buf;
+    qsv->opaque_alloc_type  = q->req.Type;
+
+    return 0;
+}
+
 int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
 {
+    int opaque_alloc = 0;
     int ret;
 
     q->param.IOPattern  = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
@@ -247,6 +285,8 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
 
         q->session         = qsv->session;
         q->param.IOPattern = qsv->iopattern;
+
+        opaque_alloc = qsv->opaque_alloc;
     }
 
     if (!q->session) {
@@ -276,11 +316,17 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
         return ff_qsv_error(ret);
     }
 
+    if (opaque_alloc) {
+        ret = qsv_init_opaque_alloc(avctx, q);
+        if (ret < 0)
+            return ret;
+    }
+
     if (avctx->hwaccel_context) {
         AVQSVContext *qsv = avctx->hwaccel_context;
         int i, j;
 
-        q->extparam = av_mallocz_array(qsv->nb_ext_buffers + FF_ARRAY_ELEMS(q->extparam_internal),
+        q->extparam = av_mallocz_array(qsv->nb_ext_buffers + q->nb_extparam_internal,
                                        sizeof(*q->extparam));
         if (!q->extparam)
             return AVERROR(ENOMEM);
@@ -290,7 +336,7 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
             q->param.ExtParam[i] = qsv->ext_buffers[i];
         q->param.NumExtParam = qsv->nb_ext_buffers;
 
-        for (i = 0; i < FF_ARRAY_ELEMS(q->extparam_internal); i++) {
+        for (i = 0; i < q->nb_extparam_internal; i++) {
             for (j = 0; j < qsv->nb_ext_buffers; j++) {
                 if (qsv->ext_buffers[j]->BufferId == q->extparam_internal[i]->BufferId)
                     break;
@@ -302,7 +348,7 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
         }
     } else {
         q->param.ExtParam    = q->extparam_internal;
-        q->param.NumExtParam = FF_ARRAY_ELEMS(q->extparam_internal);
+        q->param.NumExtParam = q->nb_extparam_internal;
     }
 
     ret = MFXVideoENCODE_Init(q->session, &q->param);
@@ -600,6 +646,9 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q)
     av_fifo_free(q->async_fifo);
     q->async_fifo = NULL;
 
+    av_freep(&q->opaque_surfaces);
+    av_buffer_unref(&q->opaque_alloc_buf);
+
     av_freep(&q->extparam);
 
     return 0;
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index 13f1419a767183f21c2c16937d421b311f81597e..3dd7afe04173495deb3e8699e06a1c0074937e03 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -52,10 +52,15 @@ typedef struct QSVEncContext {
     mfxExtCodingOption  extco;
 #if QSV_VERSION_ATLEAST(1,6)
     mfxExtCodingOption2 extco2;
-    mfxExtBuffer  *extparam_internal[2];
-#else
-    mfxExtBuffer  *extparam_internal[1];
 #endif
+
+    mfxExtOpaqueSurfaceAlloc opaque_alloc;
+    mfxFrameSurface1       **opaque_surfaces;
+    AVBufferRef             *opaque_alloc_buf;
+
+    mfxExtBuffer  *extparam_internal[3];
+    int         nb_extparam_internal;
+
     mfxExtBuffer **extparam;
 
     AVFifoBuffer *async_fifo;