summaryrefslogtreecommitdiffstats
path: root/contrib/ffmpeg/A00-qsv.patch
diff options
context:
space:
mode:
authorRodeo <[email protected]>2013-08-22 20:34:44 +0000
committerRodeo <[email protected]>2013-08-22 20:34:44 +0000
commit3326f988806a5decae025727784a19c8cc223833 (patch)
treecd75adb1975d223d7a0fd43a31030a78939e73d3 /contrib/ffmpeg/A00-qsv.patch
parentd41905d539046445e1b81499ff7bd04d170c91d4 (diff)
Big merge, QSV to trunk: part 2 (new files).
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5738 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'contrib/ffmpeg/A00-qsv.patch')
-rw-r--r--contrib/ffmpeg/A00-qsv.patch2285
1 files changed, 2285 insertions, 0 deletions
diff --git a/contrib/ffmpeg/A00-qsv.patch b/contrib/ffmpeg/A00-qsv.patch
new file mode 100644
index 000000000..908033617
--- /dev/null
+++ b/contrib/ffmpeg/A00-qsv.patch
@@ -0,0 +1,2285 @@
+diff -Naur ../../libav-v9.6/configure ./configure
+--- ../../libav-v9.6/configure 2013-05-12 08:39:07.000000000 +0200
++++ ./configure 2013-08-14 10:48:00.520497159 +0200
+@@ -133,6 +133,7 @@
+ --enable-vaapi enable VAAPI code
+ --enable-vda enable VDA code
+ --enable-vdpau enable VDPAU code
++ --enable-qsv enable QSV code
+
+ Individual component options:
+ --disable-everything disable all components listed below
+@@ -1076,6 +1077,7 @@
+ vaapi
+ vda
+ vdpau
++ qsv
+ version3
+ xmm_clobber_test
+ x11grab
+@@ -1629,6 +1631,7 @@
+ wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel"
+ wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel"
+ wmv3_vdpau_decoder_select="vc1_vdpau_decoder"
++h264_qsv_decoder_select="qsv h264_decoder"
+
+ # parsers
+ h264_parser_select="error_resilience golomb h264dsp h264pred mpegvideo"
+@@ -3584,6 +3587,12 @@
+ check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
+ { echolog "Please upgrade to libvdpau >= 0.2 if you would like vdpau support." && disable vdpau; }
+ fi
++if enabled qsv; then
++ disable qsv
++ check_header msdk/mfxvideo.h && enable qsv
++else
++ disable qsv
++fi
+
+ enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel"
+
+@@ -3795,6 +3804,7 @@
+ echo "libdxva2 enabled ${dxva2-no}"
+ echo "libva enabled ${vaapi-no}"
+ echo "libvdpau enabled ${vdpau-no}"
++echo "libqsv enabled ${qsv-no}"
+ echo "AVISynth enabled ${avisynth-no}"
+ echo "frei0r enabled ${frei0r-no}"
+ echo "gnutls enabled ${gnutls-no}"
+diff -Naur ../../libav-v9.6/libavcodec/allcodecs.c ./libavcodec/allcodecs.c
+--- ../../libav-v9.6/libavcodec/allcodecs.c 2013-05-12 08:39:07.000000000 +0200
++++ ./libavcodec/allcodecs.c 2013-08-14 10:48:00.520497159 +0200
+@@ -143,6 +143,7 @@
+ REGISTER_DECODER(H263I, h263i);
+ REGISTER_ENCODER(H263P, h263p);
+ REGISTER_DECODER(H264, h264);
++ REGISTER_DECODER(H264_QSV, h264_qsv);
+ REGISTER_DECODER(H264_VDPAU, h264_vdpau);
+ REGISTER_ENCDEC (HUFFYUV, huffyuv);
+ REGISTER_DECODER(IDCIN, idcin);
+diff -Naur ../../libav-v9.6/libavcodec/Makefile ./libavcodec/Makefile
+--- ../../libav-v9.6/libavcodec/Makefile 2013-05-12 08:39:07.000000000 +0200
++++ ./libavcodec/Makefile 2013-08-14 10:48:00.521497282 +0200
+@@ -10,6 +10,7 @@
+ vdpau.h \
+ version.h \
+ xvmc.h \
++ qsv.h \
+
+ OBJS = allcodecs.o \
+ audioconvert.o \
+@@ -196,6 +197,7 @@
+ h264_loopfilter.o h264_direct.o \
+ cabac.o h264_sei.o h264_ps.o \
+ h264_refs.o h264_cavlc.o h264_cabac.o
++OBJS-$(CONFIG_H264_QSV_DECODER) += qsv_h264.o qsv.o
+ OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o
+ OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o
+ OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_h264.o
+diff -Naur ../../libav-v9.6/libavcodec/qsv.c ./libavcodec/qsv.c
+--- ../../libav-v9.6/libavcodec/qsv.c 1970-01-01 01:00:00.000000000 +0100
++++ ./libavcodec/qsv.c 2013-08-19 21:32:01.704244071 +0200
+@@ -0,0 +1,646 @@
++/* ********************************************************************* *\
++
++Copyright (C) 2013 Intel Corporation. All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++- Redistributions of source code must retain the above copyright notice,
++this list of conditions and the following disclaimer.
++- Redistributions in binary form must reproduce the above copyright notice,
++this list of conditions and the following disclaimer in the documentation
++and/or other materials provided with the distribution.
++- Neither the name of Intel Corporation nor the names of its contributors
++may be used to endorse or promote products derived from this software
++without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR
++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT,
++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++\* ********************************************************************* */
++
++#include "qsv.h"
++
++#include "avcodec.h"
++#include "internal.h"
++
++int av_qsv_get_free_encode_task(av_qsv_list * tasks)
++{
++ int ret = MFX_ERR_NOT_FOUND;
++ int i = 0;
++ if (tasks)
++ for (i = 0; i < av_qsv_list_count(tasks); i++) {
++ av_qsv_task *task = av_qsv_list_item(tasks, i);
++ if (task->stage && task->stage->out.sync)
++ if (!(*task->stage->out.sync->p_sync)) {
++ ret = i;
++ break;
++ }
++ }
++ return ret;
++}
++
++int av_qsv_get_free_sync(av_qsv_space * space, av_qsv_context * qsv)
++{
++ int ret = -1;
++ int counter = 0;
++
++ while (1) {
++ for (int i = 0; i < space->sync_num; i++) {
++ if (!(*(space->p_syncp[i]->p_sync)) &&
++ 0 == space->p_syncp[i]->in_use ) {
++ if (i > space->sync_num_max_used)
++ space->sync_num_max_used = i;
++ ff_qsv_atomic_inc(&space->p_syncp[i]->in_use);
++ return i;
++ }
++ }
++#if HAVE_THREADS
++ if (++counter >= AV_QSV_REPEAT_NUM_DEFAULT) {
++#endif
++ av_log(NULL, AV_LOG_FATAL, "not enough to have %d sync point(s) allocated\n",
++ space->sync_num);
++ break;
++#if HAVE_THREADS
++ }
++ av_qsv_sleep(5);
++#endif
++ }
++ return ret;
++}
++
++int av_qsv_get_free_surface(av_qsv_space * space, av_qsv_context * qsv,
++ mfxFrameInfo * info, av_qsv_split part)
++{
++ int ret = -1;
++ int from = 0;
++ int up = space->surface_num;
++ int counter = 0;
++
++ while (1) {
++ from = 0;
++ up = space->surface_num;
++ if (part == QSV_PART_LOWER)
++ up /= 2;
++ if (part == QSV_PART_UPPER)
++ from = up / 2;
++
++ for (int i = from; i < up; i++) {
++ if (0 == space->p_surfaces[i]->Data.Locked) {
++ memcpy(&(space->p_surfaces[i]->Info), info,
++ sizeof(mfxFrameInfo));
++ if (i > space->surface_num_max_used)
++ space->surface_num_max_used = i;
++ return i;
++ }
++ }
++#if HAVE_THREADS
++ if (++counter >= AV_QSV_REPEAT_NUM_DEFAULT) {
++#endif
++ av_log(NULL, AV_LOG_FATAL,
++ "not enough to have %d surface(s) allocated\n", up);
++ break;
++#if HAVE_THREADS
++ }
++ av_qsv_sleep(5);
++#endif
++ }
++ return ret;
++}
++
++int ff_qsv_is_surface_in_pipe(mfxFrameSurface1 * p_surface, av_qsv_context * qsv)
++{
++ int ret = 0;
++ int a, b,i;
++ av_qsv_list *list = 0;
++ av_qsv_stage *stage = 0;
++
++ if (!p_surface)
++ return ret;
++ if (!qsv->pipes)
++ return ret;
++
++ for (a = 0; a < av_qsv_list_count(qsv->pipes); a++) {
++ list = av_qsv_list_item(qsv->pipes, a);
++ for (b = 0; b < av_qsv_list_count(list); b++) {
++ stage = av_qsv_list_item(list, b);
++ if (p_surface == stage->out.p_surface)
++ return (stage->type << 16) | 2;
++ if (p_surface == stage->in.p_surface)
++ return (stage->type << 16) | 1;
++ }
++ }
++ return ret;
++}
++
++int ff_qsv_is_sync_in_pipe(mfxSyncPoint * sync, av_qsv_context * qsv)
++{
++ int ret = 0;
++ int a, b;
++ av_qsv_list *list = 0;
++ av_qsv_stage *stage = 0;
++
++ if (!sync)
++ return ret;
++ if (!qsv->pipes)
++ return ret;
++
++ for (a = 0; a < av_qsv_list_count(qsv->pipes); a++) {
++ list = av_qsv_list_item(qsv->pipes, a);
++ for (b = 0; b < av_qsv_list_count(list); b++) {
++ stage = av_qsv_list_item(list, b);
++ if (sync == stage->out.sync->p_sync) {
++ return 1;
++ }
++ }
++ }
++ return ret;
++}
++
++av_qsv_stage *av_qsv_stage_init(void)
++{
++ av_qsv_stage *stage = av_mallocz(sizeof(av_qsv_stage));
++ return stage;
++}
++
++void av_qsv_stage_clean(av_qsv_stage ** stage)
++{
++ if ((*stage)->out.sync) {
++ if ((*stage)->out.sync->p_sync)
++ *(*stage)->out.sync->p_sync = 0;
++ if ((*stage)->out.sync->in_use > 0)
++ ff_qsv_atomic_dec(&(*stage)->out.sync->in_use);
++ (*stage)->out.sync = 0;
++ }
++ if ((*stage)->out.p_surface) {
++ (*stage)->out.p_surface = 0;
++
++ }
++ if ((*stage)->in.p_surface) {
++ (*stage)->in.p_surface = 0;
++ }
++
++ av_freep(stage);
++}
++
++void av_qsv_add_context_usage(av_qsv_context * qsv, int is_threaded)
++{
++ int is_active = 0;
++#if HAVE_THREADS
++ int mut_ret = 0;
++#endif
++
++ is_active = ff_qsv_atomic_inc(&qsv->is_context_active);
++ if (is_active == 1) {
++ memset(&qsv->mfx_session, 0, sizeof(mfxSession));
++ av_qsv_pipe_list_create(&qsv->pipes, is_threaded);
++
++ qsv->dts_seq = av_qsv_list_init(is_threaded);
++
++#if HAVE_THREADS
++ if (is_threaded) {
++ qsv->qts_seq_mutex = av_mallocz(sizeof(pthread_mutex_t));
++ if (qsv->qts_seq_mutex){
++ mut_ret = pthread_mutex_init(qsv->qts_seq_mutex, NULL);
++ if(mut_ret)
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_init issue[%d] at %s\n",mut_ret,__FUNCTION__);
++ }
++
++ } else
++#endif
++ qsv->qts_seq_mutex = 0;
++ }
++}
++
++int av_qsv_context_clean(av_qsv_context * qsv)
++{
++ int is_active = 0;
++ mfxStatus sts = MFX_ERR_NONE;
++#if HAVE_THREADS
++ int mut_ret = 0;
++#endif
++
++ is_active = ff_qsv_atomic_dec(&qsv->is_context_active);
++
++ // spaces would have to be cleaned on the own,
++ // here we care about the rest, common stuff
++ if (is_active == 0) {
++
++ if (qsv->dts_seq) {
++ while (av_qsv_list_count(qsv->dts_seq))
++ av_qsv_dts_pop(qsv);
++
++ av_qsv_list_close(&qsv->dts_seq);
++ }
++#if HAVE_THREADS
++ if (qsv->qts_seq_mutex) {
++ mut_ret = pthread_mutex_destroy(qsv->qts_seq_mutex);
++ if(mut_ret)
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_destroy issue[%d] at %s\n", mut_ret,__FUNCTION__);
++#endif
++ qsv->qts_seq_mutex = 0;
++#if HAVE_THREADS
++ }
++#endif
++
++ if (qsv->pipes)
++ av_qsv_pipe_list_clean(&qsv->pipes);
++
++ if (qsv->mfx_session) {
++ sts = MFXClose(qsv->mfx_session);
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++ qsv->mfx_session = 0;
++ }
++ }
++ return 0;
++}
++
++void av_qsv_pipe_list_create(av_qsv_list ** list, int is_threaded)
++{
++ if (!*list)
++ *list = av_qsv_list_init(is_threaded);
++}
++
++void av_qsv_pipe_list_clean(av_qsv_list ** list)
++{
++ av_qsv_list *stage;
++ int i = 0;
++ if (*list) {
++ for (i = av_qsv_list_count(*list); i > 0; i--) {
++ stage = av_qsv_list_item(*list, i - 1);
++ av_qsv_flush_stages(*list, &stage);
++ }
++ av_qsv_list_close(list);
++ }
++}
++
++void av_qsv_add_stagee(av_qsv_list ** list, av_qsv_stage * stage, int is_threaded)
++{
++ if (!*list)
++ *list = av_qsv_list_init(is_threaded);
++ av_qsv_list_add(*list, stage);
++}
++
++av_qsv_stage *av_qsv_get_last_stage(av_qsv_list * list)
++{
++ av_qsv_stage *stage = 0;
++ int size = 0;
++
++ av_qsv_list_lock(list);
++ size = av_qsv_list_count(list);
++ if (size > 0)
++ stage = av_qsv_list_item(list, size - 1);
++ av_qsv_list_unlock(list);
++
++ return stage;
++}
++
++void av_qsv_flush_stages(av_qsv_list * list, av_qsv_list ** item)
++{
++ int i = 0;
++ int x = 0;
++ av_qsv_stage *stage = 0;
++ av_qsv_list *to_remove_list = 0;
++ av_qsv_list *to_remove_atom_list = 0;
++ av_qsv_list *to_remove_atom = 0;
++
++ for (i = 0; i < av_qsv_list_count(*item); i++) {
++ stage = av_qsv_list_item(*item, i);
++ if(stage->pending){
++ if(!to_remove_list)
++ to_remove_list = av_qsv_list_init(0);
++ av_qsv_list_add(to_remove_list, stage->pending);
++ }
++ av_qsv_stage_clean(&stage);
++ // should actually remove from the list but ok...
++ }
++ av_qsv_list_rem(list, *item);
++ av_qsv_list_close(item);
++
++ if(to_remove_list){
++ for (i = av_qsv_list_count(to_remove_list); i > 0; i--){
++ to_remove_atom_list = av_qsv_list_item(to_remove_list, i-1);
++ for (x = av_qsv_list_count(to_remove_atom_list); x > 0; x--){
++ to_remove_atom = av_qsv_list_item(to_remove_atom_list, x-1);
++ av_qsv_flush_stages(list,&to_remove_atom);
++ }
++ }
++ av_qsv_list_close(&to_remove_list);
++ }
++}
++
++av_qsv_list *av_qsv_pipe_by_stage(av_qsv_list * list, av_qsv_stage * stage)
++{
++ av_qsv_list *item = 0;
++ av_qsv_stage *cur_stage = 0;
++ int i = 0;
++ int a = 0;
++ for (i = 0; i < av_qsv_list_count(list); i++) {
++ item = av_qsv_list_item(list, i);
++ for (a = 0; a < av_qsv_list_count(item); a++) {
++ cur_stage = av_qsv_list_item(item, a);
++ if (cur_stage == stage)
++ return item;
++ }
++ }
++ return 0;
++}
++
++// no duplicate of the same value, if end == 0 : working over full length
++void av_qsv_dts_ordered_insert(av_qsv_context * qsv, int start, int end,
++ int64_t dts, int iter)
++{
++ av_qsv_dts *cur_dts = 0;
++ av_qsv_dts *new_dts = 0;
++ int i = 0;
++#if HAVE_THREADS
++ int mut_ret = 0;
++#endif
++
++
++#if HAVE_THREADS
++ if (iter == 0 && qsv->qts_seq_mutex){
++ mut_ret = pthread_mutex_lock(qsv->qts_seq_mutex);
++ if(mut_ret)
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_lock issue[%d] at %s\n",mut_ret, __FUNCTION__);
++ }
++#endif
++
++ if (end == 0)
++ end = av_qsv_list_count(qsv->dts_seq);
++
++ if (end <= start) {
++ new_dts = av_mallocz(sizeof(av_qsv_dts));
++ if( new_dts ) {
++ new_dts->dts = dts;
++ av_qsv_list_add(qsv->dts_seq, new_dts);
++ }
++ } else
++ for (i = end; i > start; i--) {
++ cur_dts = av_qsv_list_item(qsv->dts_seq, i - 1);
++ if (cur_dts->dts < dts) {
++ new_dts = av_mallocz(sizeof(av_qsv_dts));
++ if( new_dts ) {
++ new_dts->dts = dts;
++ av_qsv_list_insert(qsv->dts_seq, i, new_dts);
++ }
++ break;
++ } else if (cur_dts->dts == dts)
++ break;
++ }
++#if HAVE_THREADS
++ if (iter == 0 && qsv->qts_seq_mutex){
++ mut_ret = pthread_mutex_unlock(qsv->qts_seq_mutex);
++ if(mut_ret)
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_unlock issue[%d] at %s\n",mut_ret, __FUNCTION__);
++ }
++#endif
++}
++
++void av_qsv_dts_pop(av_qsv_context * qsv)
++{
++ av_qsv_dts *item = 0;
++#if HAVE_THREADS
++ int mut_ret = 0;
++#endif
++
++#if HAVE_THREADS
++ if (qsv && qsv->qts_seq_mutex){
++ mut_ret = pthread_mutex_lock(qsv->qts_seq_mutex);
++ if(mut_ret)
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_lock issue[%d] at %s\n",mut_ret, __FUNCTION__);
++ }
++#endif
++
++ if (av_qsv_list_count(qsv->dts_seq)) {
++ item = av_qsv_list_item(qsv->dts_seq, 0);
++ av_qsv_list_rem(qsv->dts_seq, item);
++ av_free(item);
++ }
++#if HAVE_THREADS
++ if (qsv && qsv->qts_seq_mutex){
++ mut_ret = pthread_mutex_unlock(qsv->qts_seq_mutex);
++ if(mut_ret)
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_lock issue[%d] at %s\n",mut_ret, __FUNCTION__);
++ }
++#endif
++}
++
++
++av_qsv_list *av_qsv_list_init(int is_threaded)
++{
++ av_qsv_list *l;
++#if HAVE_THREADS
++ int mut_ret;
++#endif
++
++ l = av_mallocz(sizeof(av_qsv_list));
++ if (!l)
++ return 0;
++ l->items = av_mallocz(AV_QSV_JOB_SIZE_DEFAULT * sizeof(void *));
++ if (!l->items)
++ return 0;
++ l->items_alloc = AV_QSV_JOB_SIZE_DEFAULT;
++
++#if HAVE_THREADS
++ if (is_threaded) {
++ l->mutex = av_mallocz(sizeof(pthread_mutex_t));
++ if (l->mutex){
++ mut_ret = pthread_mutexattr_init(&l->mta);
++ if( mut_ret )
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutexattr_init issue[%d] at %s\n",mut_ret, __FUNCTION__);
++ mut_ret = pthread_mutexattr_settype(&l->mta, PTHREAD_MUTEX_RECURSIVE /*PTHREAD_MUTEX_ERRORCHECK*/);
++ if( mut_ret )
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutexattr_settype issue[%d] at %s\n",mut_ret, __FUNCTION__);
++ mut_ret = pthread_mutex_init(l->mutex, &l->mta);
++ if( mut_ret )
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_init issue[%d] at %s\n",mut_ret, __FUNCTION__);
++ }
++ } else
++#endif
++ l->mutex = 0;
++ return l;
++}
++
++int av_qsv_list_count(av_qsv_list * l)
++{
++ int count;
++
++ av_qsv_list_lock(l);
++ count = l->items_count;
++ av_qsv_list_unlock(l);
++ return count;
++}
++
++int av_qsv_list_add(av_qsv_list * l, void *p)
++{
++ int pos = -1;
++
++ if (!p) {
++ return pos;
++ }
++
++ av_qsv_list_lock(l);
++
++ if (l->items_count == l->items_alloc) {
++ /* We need a bigger boat */
++ l->items_alloc += AV_QSV_JOB_SIZE_DEFAULT;
++ l->items = av_realloc(l->items, l->items_alloc * sizeof(void *));
++ }
++
++ l->items[l->items_count] = p;
++ pos = (l->items_count);
++ l->items_count++;
++
++ av_qsv_list_unlock(l);
++
++ return pos;
++}
++
++void av_qsv_list_rem(av_qsv_list * l, void *p)
++{
++ int i;
++
++ av_qsv_list_lock(l);
++
++ /* Find the item in the list */
++ for (i = 0; i < l->items_count; i++) {
++ if (l->items[i] == p) {
++ /* Shift all items after it sizeof( void * ) bytes earlier */
++ memmove(&l->items[i], &l->items[i + 1],
++ (l->items_count - i - 1) * sizeof(void *));
++
++ l->items_count--;
++ break;
++ }
++ }
++
++ av_qsv_list_unlock(l);
++}
++
++void *av_qsv_list_item(av_qsv_list * l, int i)
++{
++ void *ret = NULL;
++
++ if (i < 0)
++ return NULL;
++
++ av_qsv_list_lock(l);
++ if( i < l->items_count)
++ ret = l->items[i];
++ av_qsv_list_unlock(l);
++ return ret;
++}
++
++void av_qsv_list_insert(av_qsv_list * l, int pos, void *p)
++{
++
++ if (!p)
++ return;
++
++ av_qsv_list_lock(l);
++
++ if (l->items_count == l->items_alloc) {
++ l->items_alloc += AV_QSV_JOB_SIZE_DEFAULT;
++ l->items = av_realloc(l->items, l->items_alloc * sizeof(void *));
++ }
++
++ if (l->items_count != pos) {
++ memmove(&l->items[pos + 1], &l->items[pos],
++ (l->items_count - pos) * sizeof(void *));
++ }
++
++ l->items[pos] = p;
++ l->items_count--;
++
++ av_qsv_list_unlock(l);
++}
++
++void av_qsv_list_close(av_qsv_list ** _l)
++{
++ av_qsv_list *l = *_l;
++#if HAVE_THREADS
++ int mut_ret;
++#endif
++
++ av_qsv_list_lock(l);
++
++ av_free(l->items);
++
++#if HAVE_THREADS
++ if (l->mutex){
++ mut_ret = pthread_mutex_unlock(l->mutex);
++ if( mut_ret )
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_unlock issue[%d] at %s\n",mut_ret, __FUNCTION__);
++ mut_ret = pthread_mutex_destroy(&l->mutex);
++ mut_ret = pthread_mutexattr_destroy(&l->mta);
++ }
++#endif
++ av_freep(_l);
++}
++
++int av_qsv_list_lock(av_qsv_list *l){
++ int ret = 0;
++#if HAVE_THREADS
++ if (l->mutex){
++ ret = pthread_mutex_lock(l->mutex);
++ if( ret )
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_lock issue[%d] at %s\n",ret, __FUNCTION__);
++ }
++#endif
++ return ret;
++}
++
++int av_qsv_list_unlock(av_qsv_list *l){
++ int ret = 0;
++#if HAVE_THREADS
++ if (l->mutex){
++ ret = pthread_mutex_unlock(l->mutex);
++ if( ret )
++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_unlock issue[%d] at %s\n",ret, __FUNCTION__);
++ }
++#endif
++ return ret;
++}
++
++int av_is_qsv_available(mfxIMPL impl, mfxVersion * ver)
++{
++ mfxStatus sts = MFX_ERR_NONE;
++ mfxSession mfx_session;
++
++ memset(&mfx_session, 0, sizeof(mfxSession));
++ sts = MFXInit(impl, ver, &mfx_session);
++ if (sts >= 0)
++ MFXClose(mfx_session);
++ return sts;
++}
++
++void av_qsv_wait_on_sync(av_qsv_context *qsv, av_qsv_stage *stage)
++{
++ int iter = 0;
++ mfxStatus sts = MFX_ERR_NONE;
++ if( stage )
++ if(*stage->out.sync->p_sync){
++ while(1){
++ iter++;
++ sts = MFXVideoCORE_SyncOperation(qsv->mfx_session,*stage->out.sync->p_sync, AV_QSV_SYNC_TIME_DEFAULT);
++ if(MFX_WRN_IN_EXECUTION == sts){
++
++ if(iter>20)
++ AV_QSV_DEBUG_ASSERT(1, "Sync failed");
++
++ av_qsv_sleep(10);
++ continue;
++ }
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++ break;
++ }
++ }
++}
+\ No newline at end of file
+diff -Naur ../../libav-v9.6/libavcodec/qsv.h ./libavcodec/qsv.h
+--- ../../libav-v9.6/libavcodec/qsv.h 1970-01-01 01:00:00.000000000 +0100
++++ ./libavcodec/qsv.h 2013-08-19 21:32:01.709244686 +0200
+@@ -0,0 +1,494 @@
++/* ********************************************************************* *\
++
++Copyright (C) 2013 Intel Corporation. All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++- Redistributions of source code must retain the above copyright notice,
++this list of conditions and the following disclaimer.
++- Redistributions in binary form must reproduce the above copyright notice,
++this list of conditions and the following disclaimer in the documentation
++and/or other materials provided with the distribution.
++- Neither the name of Intel Corporation nor the names of its contributors
++may be used to endorse or promote products derived from this software
++without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR
++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT,
++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++\* ********************************************************************* */
++
++#ifndef AVCODEC_QSV_H
++#define AVCODEC_QSV_H
++
++/**
++ * @file
++ * @ingroup lavc_codec_hwaccel_qsv
++ * Common header for QSV/MediaSDK acceleration
++ */
++
++/**
++ * @defgroup lavc_codec_hwaccel_qsv QSV/MediaSDK based Decode/Encode and VPP
++ * @ingroup lavc_codec_hwaccel
++ *
++ * As Intel Quick Sync Video (QSV) can decode/preprocess/encode with HW
++ * acceleration.
++ *
++ * Supported features:
++ * - access:
++ * - format AV_PIX_FMT_QSV_H264, AVCodec decoder based implementation
++ * - name "h264_qsv", avcodec_find_decoder_by_name( "h264_qsv")
++ * - IO Pattern:
++ * - Opaque memory: MFX_IOPATTERN_OUT_OPAQUE_MEMORY // Video memory is
++ * MFX_IMPL_HARDWARE or MFX_IMPL_AUTO and runtime support,
++ * otherwise: System Memory
++ * - System memory: MFX_IOPATTERN_OUT_SYSTEM_MEMORY
++ * - Allocators:
++ * - default allocator for System memory: MFX_MEMTYPE_SYSTEM_MEMORY
++ * - details:
++ * implementation as "per frame"
++ *
++ * TODO list:
++ * - access:
++ * - format AV_PIX_FMT_QSV_MPEG2
++ * - format AV_PIX_FMT_QSV_VC1
++ * - format AV_PIX_FMT_QSV, see "details" below
++ * - IO Pattern:
++ * - VIDEO_MEMORY // MFX_IOPATTERN_OUT_VIDEO_MEMORY
++ * - Allocators:
++ * - Video memory: MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET /
++ * MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET
++ * - details:
++ * "per slice" support: AV_PIX_FMT_QSV with AVHWAccel based implementation
++ *
++ * Note av_qsv_config struct required to fill in via
++ * AVCodecContext.hwaccel_context
++ *
++ * As per frame, note AVFrame.data[2] (qsv_atom) used for frame atom id,
++ * data/linesize should be used together with SYSTEM_MEMORY and tested
++ *
++ * Note: Compilation would require:
++ * - Intel MediaSDK headers, Full SDK is avaialble from the original web site:
++ * http://software.intel.com/en-us/vcsource/tools/media-SDK
++ * Will be referenced as msdk/*.h (mfxdefs.h, mfxstructures.h, ... )
++ * and
++ * - Final application has to link against Intel MediaSDK dispatcher, available
++ * at MediaSDK as well
++ *
++ * Target OS: as per available dispatcher and driver support
++ *
++ * Implementation details:
++ * Provided struct av_qsv_context contain several struct av_qsv_space(s) for decode,
++ * VPP and encode.
++ * av_qsv_space just contain needed environment for the appropriate action.
++ * Based on this - pipeline (see pipes) will be build to pass details such as
++ * mfxFrameSurface1* and mfxSyncPoint* from one action to the next.
++ *
++ * Resources re-usage (av_qsv_flush_stages):
++ * av_qsv_context *qsv = (av_qsv_context *)video_codec_ctx->priv_data;
++ * av_qsv_list *pipe = (av_qsv_list *)video_frame->data[2];
++ * av_qsv_flush_stages( qsv->pipes, &pipe );
++ *
++ * DTS re-usage:
++ * av_qsv_dts_pop(qsv);
++ *
++ * for video,DX9/11 memory it has to be Unlock'ed as well
++ *
++ * Implementation is thread aware and uses synchronization point(s) from MediaSDK
++ * as per configuration.
++ *
++ * For the details of MediaSDK usage and options available - please refer to the
++ * available documentation at MediaSDK.
++ *
++ * Feature set used from MSDK is defined by AV_QSV_MSDK_VERSION_MAJOR and
++ * AV_QSV_MSDK_VERSION_MINOR
++ *
++ * @{
++ */
++
++#include <stdint.h>
++#include <string.h>
++#include "msdk/mfxvideo.h"
++#include "libavutil/mem.h"
++#include "libavutil/time.h"
++
++#ifdef HAVE_AV_CONFIG_H
++#include "config.h"
++#endif
++
++#if HAVE_THREADS
++#if defined (__GNUC__)
++#include <pthread.h>
++#define ff_qsv_atomic_inc(ptr) __sync_add_and_fetch(ptr,1)
++#define ff_qsv_atomic_dec(ptr) __sync_sub_and_fetch (ptr,1)
++#elif HAVE_WINDOWS_H // MSVC case
++#include <windows.h>
++#if HAVE_PTHREADS
++#include <pthread.h>
++#elif HAVE_W32THREADS
++#include "w32pthreads.h"
++#endif
++#define ff_qsv_atomic_inc(ptr) InterlockedIncrement(ptr)
++#define ff_qsv_atomic_dec(ptr) InterlockedDecrement (ptr)
++#else
++// targeting only for MinGW or MSVC
++#endif
++
++#else
++#define ff_qsv_atomic_inc(ptr) ((*ptr)++)
++#define ff_qsv_atomic_dec(ptr) ((*ptr)--)
++#endif
++
++
++// sleep is defined in milliseconds
++#define av_qsv_sleep(x) av_usleep((x)*1000)
++
++#define AV_QSV_ZERO_MEMORY(VAR) {memset(&VAR, 0, sizeof(VAR));}
++#define AV_QSV_ALIGN32(X) (((mfxU32)((X)+31)) & (~ (mfxU32)31))
++#define AV_QSV_ALIGN16(value) (((value + 15) >> 4) << 4)
++#ifndef AV_QSV_PRINT_RET_MSG
++#define AV_QSV_PRINT_RET_MSG(ERR) { av_log(NULL, AV_LOG_FATAL,"Error code %d,\t%s\t%d\n", ERR, __FUNCTION__, __LINE__); }
++#endif
++
++#ifndef AV_QSV_DEBUG_ASSERT
++#define AV_QSV_DEBUG_ASSERT(x,y) {if ((x)) {av_log(NULL, AV_LOG_FATAL,"\nASSERT: %s\n",y);};}
++#endif
++
++#define AV_QSV_CHECK_RESULT(P, X, ERR) {if ((X) > (P)) {AV_QSV_PRINT_RET_MSG(ERR); return ERR;}}
++#define AV_QSV_CHECK_POINTER(P, ERR) {if (!(P)) {AV_QSV_PRINT_RET_MSG(ERR); return ERR;}}
++#define AV_QSV_IGNORE_MFX_STS(P, X) {if ((X) == (P)) {P = MFX_ERR_NONE;}}
++
++#define AV_QSV_ID_BUFFER MFX_MAKEFOURCC('B','U','F','F')
++#define AV_QSV_ID_FRAME MFX_MAKEFOURCC('F','R','M','E')
++
++#define AV_QSV_SURFACE_NUM 80
++#define AV_QSV_SYNC_NUM AV_QSV_SURFACE_NUM*3/4
++#define AV_QSV_BUF_SIZE_DEFAULT 4096*2160*10
++#define AV_QSV_JOB_SIZE_DEFAULT 10
++#define AV_QSV_SYNC_TIME_DEFAULT 10000
++// see av_qsv_get_free_sync, av_qsv_get_free_surface , 100 if usleep(10*1000)(10ms) == 1 sec
++#define AV_QSV_REPEAT_NUM_DEFAULT 100
++#define AV_QSV_ASYNC_DEPTH_DEFAULT 4
++
++// version of MSDK/QSV API currently used
++#define AV_QSV_MSDK_VERSION_MAJOR 1
++#define AV_QSV_MSDK_VERSION_MINOR 3
++
++typedef enum AV_QSV_STAGE_TYPE {
++
++#define AV_QSV_DECODE_MASK 0x001
++ AV_QSV_DECODE = 0x001,
++
++#define AV_QSV_VPP_MASK 0x0F0
++ // "Mandatory VPP filter" , might be with "Hint-based VPP filters"
++ AV_QSV_VPP_DEFAULT = 0x010,
++ // "User Modules" etc
++ AV_QSV_VPP_USER = 0x020,
++
++#define av_QSV_ENCODE_MASK 0x100
++ AV_QSV_ENCODE = 0x100
++#define AV_QSV_ANY_MASK 0xFFF
++} AV_QSV_STAGE_TYPE;
++
++
++typedef struct av_qsv_list {
++ // practically pthread_mutex_t
++ void *mutex;
++#if HAVE_THREADS
++ pthread_mutexattr_t mta;
++#endif
++
++ void **items;
++ int items_alloc;
++
++ int items_count;
++} av_qsv_list;
++
++typedef struct av_qsv_sync {
++ mfxSyncPoint* p_sync;
++ int in_use;
++} av_qsv_sync;
++
++typedef struct av_qsv_stage {
++ AV_QSV_STAGE_TYPE type;
++ struct {
++ mfxBitstream *p_bs;
++ mfxFrameSurface1 *p_surface;
++ } in;
++ struct {
++ mfxBitstream *p_bs;
++ mfxFrameSurface1 *p_surface;
++ av_qsv_sync *sync;
++ } out;
++ av_qsv_list *pending;
++} av_qsv_stage;
++
++typedef struct av_qsv_task {
++ mfxBitstream *bs;
++ av_qsv_stage *stage;
++} av_qsv_task;
++
++
++typedef struct av_qsv_space {
++
++ uint8_t is_init_done;
++
++ AV_QSV_STAGE_TYPE type;
++
++ mfxVideoParam m_mfxVideoParam;
++
++ mfxFrameAllocResponse response;
++ mfxFrameAllocRequest request[2]; // [0] - in, [1] - out, if needed
++
++ mfxExtOpaqueSurfaceAlloc ext_opaque_alloc;
++ mfxExtBuffer **p_ext_params;
++ uint16_t p_ext_param_num;
++
++ uint16_t surface_num_max_used;
++ uint16_t surface_num;
++ mfxFrameSurface1 *p_surfaces[AV_QSV_SURFACE_NUM];
++
++ uint16_t sync_num_max_used;
++ uint16_t sync_num;
++ av_qsv_sync *p_syncp[AV_QSV_SYNC_NUM];
++
++ mfxBitstream bs;
++ uint8_t *p_buf;
++ size_t p_buf_max_size;
++
++ // only for encode and tasks
++ av_qsv_list *tasks;
++
++ av_qsv_list *pending;
++
++ // storage for allocations/mfxMemId*
++ mfxMemId *mids;
++} av_qsv_space;
++
++typedef struct av_qsv_context {
++ volatile int is_context_active;
++
++ mfxIMPL impl;
++ mfxSession mfx_session;
++ mfxVersion ver;
++
++ // decode
++ av_qsv_space *dec_space;
++ // encode
++ av_qsv_space *enc_space;
++ // vpp
++ av_qsv_list *vpp_space;
++
++ av_qsv_list *pipes;
++
++ // MediaSDK starting from API version 1.6 includes DecodeTimeStamp
++ // in addition to TimeStamp
++ // see also AV_QSV_MSDK_VERSION_MINOR , AV_QSV_MSDK_VERSION_MAJOR
++ av_qsv_list *dts_seq;
++
++ // practically pthread_mutex_t
++ void *qts_seq_mutex;
++
++ int is_anex;
++
++ void *qsv_config;
++
++} av_qsv_context;
++
++typedef enum {
++ QSV_PART_ANY = 0,
++ QSV_PART_LOWER,
++ QSV_PART_UPPER
++} av_qsv_split;
++
++typedef struct {
++ int64_t dts;
++} av_qsv_dts;
++
++typedef struct av_qsv_alloc_frame {
++ mfxU32 id;
++ mfxFrameInfo info;
++} av_qsv_alloc_frame;
++
++typedef struct av_qsv_alloc_buffer {
++ mfxU32 id;
++ mfxU32 nbytes;
++ mfxU16 type;
++} av_qsv_alloc_buffer;
++
++typedef struct av_qsv_allocators_space {
++ av_qsv_space *space;
++ mfxFrameAllocator frame_alloc;
++ mfxBufferAllocator buffer_alloc;
++} av_qsv_allocators_space;
++
++typedef struct av_qsv_config {
++ /**
++ * Set asynch depth of processing with QSV
++ * Format: 0 and more
++ *
++ * - encoding: Set by user.
++ * - decoding: Set by user.
++ */
++ int async_depth;
++
++ /**
++ * Range of numbers that indicate trade-offs between quality and speed.
++ * Format: from 1/MFX_TARGETUSAGE_BEST_QUALITY to 7/MFX_TARGETUSAGE_BEST_SPEED inclusive
++ *
++ * - encoding: Set by user.
++ * - decoding: unused
++ */
++ int target_usage;
++
++ /**
++ * Number of reference frames; if NumRefFrame = 0, this parameter is not specified.
++ * Format: 0 and more
++ *
++ * - encoding: Set by user.
++ * - decoding: unused
++ */
++ int num_ref_frame;
++
++ /**
++ * Distance between I- or P- key frames; if it is zero, the GOP structure is unspecified.
++ * Note: If GopRefDist = 1, there are no B-frames used.
++ *
++ * - encoding: Set by user.
++ * - decoding: unused
++ */
++ int gop_ref_dist;
++
++ /**
++ * Number of pictures within the current GOP (Group of Pictures); if GopPicSize=0,
++ * then the GOP size is unspecified. If GopPicSize=1, only I-frames are used.
++ *
++ * - encoding: Set by user.
++ * - decoding: unused
++ */
++ int gop_pic_size;
++
++ /**
++ * Set type of surfaces used with QSV
++ * Format: "IOPattern enum" of Media SDK
++ *
++ * - encoding: Set by user.
++ * - decoding: Set by user.
++ */
++ int io_pattern;
++
++ /**
++ * Set amount of additional surfaces might be needed
++ * Format: ammount of additional buffers(surfaces+syncs)
++ * to allocate in advance
++ *
++ * - encoding: Set by user.
++ * - decoding: Set by user.
++ */
++ int additional_buffers;
++
++ /**
++ * If pipeline should be sync.
++ * Format: wait time in milliseconds,
++ * AV_QSV_SYNC_TIME_DEFAULT/10000 might be a good value
++ *
++ * - encoding: Set by user.
++ * - decoding: Set by user.
++ */
++ int sync_need;
++
++ /**
++ * Type of implementation needed
++ *
++ * - encoding: Set by user.
++ * - decoding: Set by user.
++ */
++ int impl_requested;
++
++ /**
++ * if QSV usage is multithreaded.
++ * Format: Yes/No, 1/0
++ *
++ * - encoding: Set by user.
++ * - decoding: Set by user.
++ */
++ int usage_threaded;
++
++ /**
++ * if QSV use an external allocation (valid per session/mfxSession)
++ * Format: pointer to allocators, if default: 0
++ *
++ * note that:
++ * System Memory: can be used without provided and external allocator,
++ * meaning MediaSDK will use an internal one
++ * Video Memory: in this case - we must provide an external allocator
++ * Also, Media SDK session doesn't require external allocator if the application
++ * uses opaque memory
++ *
++ * Calls SetFrameAllocator/SetBufferAllocator
++ * (MFXVideoCORE_SetFrameAllocator/MFXVideoCORE_SetBufferAllocator)
++ * are to pass allocators to Media SDK
++ *
++ * - encoding: Set by user.
++ * - decoding: Set by user.
++ */
++ av_qsv_allocators_space *allocators;
++
++} av_qsv_config;
++
++#define ANEX_UNKNOWN 0
++#define ANEX_PREFIX 1
++#define ANEX_NO_PREFIX 2
++
++static const uint8_t ff_prefix_code[] = { 0x00, 0x00, 0x00, 0x01 };
++
++int av_qsv_get_free_sync(av_qsv_space *, av_qsv_context *);
++int av_qsv_get_free_surface(av_qsv_space *, av_qsv_context *, mfxFrameInfo *,
++ av_qsv_split);
++int av_qsv_get_free_encode_task(av_qsv_list *);
++
++int av_is_qsv_available(mfxIMPL, mfxVersion *);
++void av_qsv_wait_on_sync(av_qsv_context *, av_qsv_stage *);
++
++void av_qsv_add_context_usage(av_qsv_context *, int);
++
++void av_qsv_pipe_list_create(av_qsv_list **, int);
++void av_qsv_pipe_list_clean(av_qsv_list **);
++
++void av_qsv_add_stagee(av_qsv_list **, av_qsv_stage *, int);
++av_qsv_stage *av_qsv_get_last_stage(av_qsv_list *);
++av_qsv_list *av_qsv_pipe_by_stage(av_qsv_list *, av_qsv_stage *);
++void av_qsv_flush_stages(av_qsv_list *, av_qsv_list **);
++
++void av_qsv_dts_ordered_insert(av_qsv_context *, int, int, int64_t, int);
++void av_qsv_dts_pop(av_qsv_context *);
++
++av_qsv_stage *av_qsv_stage_init(void);
++void av_qsv_stage_clean(av_qsv_stage **);
++int av_qsv_context_clean(av_qsv_context *);
++
++int ff_qsv_is_sync_in_pipe(mfxSyncPoint *, av_qsv_context *);
++int ff_qsv_is_surface_in_pipe(mfxFrameSurface1 *, av_qsv_context *);
++
++av_qsv_list *av_qsv_list_init(int);
++int av_qsv_list_lock(av_qsv_list *);
++int av_qsv_list_unlock(av_qsv_list *);
++int av_qsv_list_add(av_qsv_list *, void *);
++void av_qsv_list_rem(av_qsv_list *, void *);
++void av_qsv_list_insert(av_qsv_list *, int, void *);
++void av_qsv_list_close(av_qsv_list **);
++
++int av_qsv_list_count(av_qsv_list *);
++void *av_qsv_list_item(av_qsv_list *, int);
++
++/* @} */
++
++#endif //AVCODEC_QSV_H
+diff -Naur ../../libav-v9.6/libavcodec/qsv_h264.c ./libavcodec/qsv_h264.c
+--- ../../libav-v9.6/libavcodec/qsv_h264.c 1970-01-01 01:00:00.000000000 +0100
++++ ./libavcodec/qsv_h264.c 2013-08-19 21:32:01.705244194 +0200
+@@ -0,0 +1,974 @@
++/* ********************************************************************* *\
++
++Copyright (C) 2013 Intel Corporation. All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++- Redistributions of source code must retain the above copyright notice,
++this list of conditions and the following disclaimer.
++- Redistributions in binary form must reproduce the above copyright notice,
++this list of conditions and the following disclaimer in the documentation
++and/or other materials provided with the distribution.
++- Neither the name of Intel Corporation nor the names of its contributors
++may be used to endorse or promote products derived from this software
++without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR
++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT,
++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++\* ********************************************************************* */
++
++#include "h264.h"
++#include "h264data.h"
++#include "qsv_h264.h"
++
++static av_qsv_config av_qsv_default_config = {
++ .async_depth = AV_QSV_ASYNC_DEPTH_DEFAULT,
++ .target_usage = MFX_TARGETUSAGE_BALANCED,
++ .num_ref_frame = 0,
++ .gop_ref_dist = 0,
++ .gop_pic_size = 0,
++ .io_pattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY,
++ .additional_buffers = 0,
++ .sync_need = 0,
++ .impl_requested = MFX_IMPL_HARDWARE,
++ .usage_threaded = 0,
++ .allocators = 0,
++};
++
++static av_qsv_allocators_space av_qsv_default_system_allocators = {
++ // fill to access mids
++ .space = 0,
++
++ .frame_alloc = {
++ .pthis = &av_qsv_default_system_allocators,
++ .Alloc = ff_qsv_mem_frame_alloc,
++ .Lock = ff_qsv_mem_frame_lock,
++ .Unlock = ff_qsv_mem_frame_unlock,
++ .GetHDL = ff_qsv_mem_frame_getHDL,
++ .Free = ff_qsv_mem_frame_free,
++ },
++ .buffer_alloc = {
++ .pthis = &av_qsv_default_system_allocators,
++ .Alloc = ff_qsv_mem_buffer_alloc,
++ .Lock = ff_qsv_mem_buffer_lock,
++ .Unlock = ff_qsv_mem_buffer_unlock,
++ .Free = ff_qsv_mem_buffer_free,
++ },
++};
++
++static const uint8_t ff_slice_code[] = { 0x00, 0x00, 0x01, 0x65 };
++
++int ff_qsv_nal_find_start_code(uint8_t * pb, size_t size)
++{
++ if ((int) size < 4)
++ return 0;
++
++ while ((4 <= size) && ((0 != pb[0]) || (0 != pb[1]) || (0 != pb[2]) || (1 != pb[3]))) {
++ pb += 1;
++ size -= 1;
++ }
++
++ if (4 <= size)
++ return 1;
++
++ return 0;
++}
++
++int ff_qsv_dec_init_clean(AVCodecContext *avctx)
++{
++ mfxStatus sts = MFX_ERR_NONE;
++ av_qsv_context *qsv = avctx->priv_data;
++ av_qsv_space *qsv_decode = qsv->dec_space;
++ av_qsv_context_clean(qsv);
++ av_freep(&avctx->priv_data);
++}
++int ff_qsv_dec_init(AVCodecContext * avctx)
++{
++ int ret = 0;
++ mfxStatus sts = MFX_ERR_NONE;
++ size_t current_offset = 6;
++ int header_size = 0;
++ unsigned char *current_position;
++ size_t current_size;
++
++ av_qsv_context *qsv = avctx->priv_data;
++ av_qsv_space *qsv_decode = qsv->dec_space;
++ av_qsv_config *qsv_config_context = avctx->hwaccel_context;
++
++ qsv->impl = qsv_config_context->impl_requested;
++
++ memset(&qsv->mfx_session, 0, sizeof(mfxSession));
++ qsv->ver.Major = AV_QSV_MSDK_VERSION_MAJOR;
++ qsv->ver.Minor = AV_QSV_MSDK_VERSION_MINOR;
++
++ sts = MFXInit(qsv->impl, &qsv->ver, &qsv->mfx_session);
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++
++ AV_QSV_ZERO_MEMORY(qsv_decode->m_mfxVideoParam);
++ AV_QSV_ZERO_MEMORY(qsv_decode->m_mfxVideoParam.mfx);
++ qsv_decode->m_mfxVideoParam.mfx.CodecId = MFX_CODEC_AVC;
++ qsv_decode->m_mfxVideoParam.IOPattern =
++ qsv_config_context->io_pattern;
++
++ qsv_decode->m_mfxVideoParam.AsyncDepth =
++ qsv_config_context->async_depth;
++
++ AV_QSV_ZERO_MEMORY(qsv_decode->bs);
++ {
++ current_position = avctx->extradata;
++ current_size = avctx->extradata_size;
++
++ if (!ff_qsv_nal_find_start_code(current_position, current_size)) {
++
++ while (current_offset <= current_size) {
++ int current_nal_size =
++ (unsigned char) current_position[current_offset] << 8 |
++ (unsigned char) current_position[current_offset + 1];
++ unsigned char nal_type =
++ (unsigned char) current_position[current_offset + 2] & 0x1F;
++
++ if (nal_type == NAL_SPS || nal_type == NAL_PPS) {
++ memcpy(&qsv_decode->p_buf[header_size], ff_prefix_code,
++ sizeof(ff_prefix_code));
++ header_size += sizeof(ff_prefix_code);
++ memcpy(&qsv_decode->p_buf[header_size],
++ &current_position[current_offset + 2],
++ current_nal_size);
++
++ // fix for PPS as it comes after SPS, so - last
++ if (nal_type == NAL_PPS) {
++ // fix of MFXVideoDECODE_DecodeHeader: needs one SLICE to find, any SLICE
++ memcpy(&qsv_decode->p_buf
++ [header_size + current_nal_size],
++ ff_slice_code, current_nal_size);
++ header_size += sizeof(ff_slice_code);
++ }
++ }
++
++ header_size += current_nal_size;
++ current_offset += current_nal_size + 3;
++ }
++ } else {
++ memcpy(&qsv_decode->p_buf[0], avctx->extradata,
++ avctx->extradata_size);
++ header_size = avctx->extradata_size;
++ memcpy(&qsv_decode->p_buf
++ [header_size], ff_slice_code, sizeof(ff_slice_code));
++ header_size += sizeof(ff_slice_code);
++ }
++ }
++
++ qsv_decode->bs.Data = qsv_decode->p_buf;
++ qsv_decode->bs.DataLength = header_size;
++ qsv_decode->bs.MaxLength = qsv_decode->p_buf_max_size;
++
++ if (qsv_decode->bs.DataLength > qsv_decode->bs.MaxLength) {
++ av_log(avctx, AV_LOG_FATAL, "DataLength > MaxLength\n");
++ return -1;
++ }
++
++ sts = MFXVideoDECODE_DecodeHeader(qsv->mfx_session, &qsv_decode->bs,
++ &qsv_decode->m_mfxVideoParam);
++
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++
++ qsv_decode->bs.DataLength -= sizeof(ff_slice_code);
++
++ memset(&qsv_decode->request, 0, sizeof(mfxFrameAllocRequest) * 2);
++ sts = MFXVideoDECODE_QueryIOSurf(qsv->mfx_session,
++ &qsv_decode->m_mfxVideoParam,
++ &qsv_decode->request);
++
++ AV_QSV_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++
++ qsv_decode->surface_num =
++ FFMIN(qsv_decode->request[0].NumFrameSuggested +
++ qsv_config_context->async_depth +
++ qsv_config_context->additional_buffers, AV_QSV_SURFACE_NUM);
++
++ if (qsv_decode->surface_num <= 0)
++ qsv_decode->surface_num = AV_QSV_SURFACE_NUM;
++
++ if (qsv_decode->m_mfxVideoParam.IOPattern ==
++ MFX_IOPATTERN_OUT_SYSTEM_MEMORY) {
++
++ // as per non-opaque memory:
++ if (!qsv_config_context->allocators) {
++ av_log(avctx, AV_LOG_INFO,
++ "Using default allocators for QSV decode\n");
++ ((av_qsv_config *) avctx->hwaccel_context)->allocators =
++ &av_qsv_default_system_allocators;
++ }
++
++ qsv_config_context->allocators->space = qsv_decode;
++
++ qsv_decode->request[0].NumFrameMin = qsv_decode->surface_num;
++ qsv_decode->request[0].NumFrameSuggested = qsv_decode->surface_num;
++
++ qsv_decode->request[0].Type = MFX_MEMTYPE_EXTERNAL_FRAME | MFX_MEMTYPE_FROM_DECODE;
++ // qsv_decode->request[0].Type |= m_bd3dAlloc ? MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET : MFX_MEMTYPE_SYSTEM_MEMORY;
++ qsv_decode->request[0].Type |= MFX_MEMTYPE_SYSTEM_MEMORY;
++
++ qsv_config_context->allocators->
++ frame_alloc.Alloc(qsv_config_context->allocators,
++ &qsv_decode->request[0],
++ &qsv_decode->response);
++ }
++
++ for (int i = 0; i < qsv_decode->surface_num; i++) {
++ qsv_decode->p_surfaces[i] = av_mallocz(sizeof(mfxFrameSurface1));
++ AV_QSV_CHECK_POINTER(qsv_decode->p_surfaces[i],
++ AVERROR(ENOMEM));
++ memcpy(&(qsv_decode->p_surfaces[i]->Info),
++ &(qsv_decode->request[0].Info), sizeof(mfxFrameInfo));
++
++ // for an external(like DX9/11) based allocation:
++ // we bind:
++ // m_pmfxSurfaces[i].Data.MemId = m_mfxResponse.mids[i];
++ // else, System memory:
++ if (qsv_decode->m_mfxVideoParam.IOPattern ==
++ MFX_IOPATTERN_OUT_SYSTEM_MEMORY) {
++ sts =
++ qsv_config_context->allocators->
++ frame_alloc.Lock(qsv_config_context->allocators,
++ qsv_decode->response.mids[i],
++ &(qsv_decode->p_surfaces[i]->Data));
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++ }
++ }
++
++ qsv_decode->sync_num = FFMIN(qsv_decode->surface_num, AV_QSV_SYNC_NUM);
++ for (int i = 0; i < qsv_decode->sync_num; i++) {
++ qsv_decode->p_syncp[i] = av_mallocz(sizeof(av_qsv_sync));
++ AV_QSV_CHECK_POINTER(qsv_decode->p_syncp[i], AVERROR(ENOMEM));
++ qsv_decode->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint));
++ AV_QSV_CHECK_POINTER(qsv_decode->p_syncp[i]->p_sync, AVERROR(ENOMEM));
++ }
++
++ memset(&qsv_decode->ext_opaque_alloc, 0,
++ sizeof(mfxExtOpaqueSurfaceAlloc));
++
++ if (qsv_decode->m_mfxVideoParam.IOPattern ==
++ MFX_IOPATTERN_OUT_OPAQUE_MEMORY) {
++ qsv_decode->m_mfxVideoParam.NumExtParam = qsv_decode->p_ext_param_num = 1;
++
++ qsv_decode->p_ext_params = av_mallocz(sizeof(mfxExtBuffer *)*qsv_decode->p_ext_param_num);
++ AV_QSV_CHECK_POINTER(qsv_decode->p_ext_params, AVERROR(ENOMEM));
++
++ qsv_decode->m_mfxVideoParam.ExtParam = qsv_decode->p_ext_params;
++
++ qsv_decode->ext_opaque_alloc.Out.Surfaces = qsv_decode->p_surfaces;
++ qsv_decode->ext_opaque_alloc.Out.NumSurface = qsv_decode->surface_num;
++ qsv_decode->ext_opaque_alloc.Out.Type = qsv_decode->request[0].Type;
++
++ qsv_decode->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
++ qsv_decode->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc);
++ qsv_decode->p_ext_params[0] = (mfxExtBuffer *) &qsv_decode->ext_opaque_alloc;
++ }
++
++ sts =
++ MFXVideoDECODE_Init(qsv->mfx_session,
++ &qsv_decode->m_mfxVideoParam);
++
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++
++ qsv_decode->is_init_done = 1;
++ return ret;
++}
++
++av_cold int ff_qsv_decode_init(AVCodecContext * avctx)
++{
++ av_qsv_context *qsv;
++ av_qsv_space *qsv_decode;
++ av_qsv_config **qsv_config_context =
++ (av_qsv_config **) & avctx->hwaccel_context;
++
++ qsv = avctx->priv_data;
++
++ if (qsv && qsv->dec_space && qsv->dec_space->is_init_done || !avctx->extradata_size)
++ return 0;
++
++ if(!qsv)
++ qsv = av_mallocz(sizeof(av_qsv_context));
++ if (!qsv)
++ return AVERROR(ENOMEM);
++
++ if(!qsv_decode)
++ qsv_decode = av_mallocz(sizeof(av_qsv_space));
++ if (!qsv_decode){
++ free(qsv);
++ return AVERROR(ENOMEM);
++ }
++ avctx->priv_data = qsv;
++ qsv->dec_space = qsv_decode;
++
++ qsv_decode->p_buf_max_size = AV_QSV_BUF_SIZE_DEFAULT;
++ if(!qsv_decode->p_buf)
++ qsv_decode->p_buf = av_malloc(qsv_decode->p_buf_max_size * sizeof(uint8_t));
++ if (!qsv_decode->p_buf)
++ return AVERROR(ENOMEM);
++
++ if (!(*qsv_config_context)) {
++ av_log(avctx, AV_LOG_INFO,
++ "Using default config for QSV decode\n");
++ avctx->hwaccel_context = &av_qsv_default_config;
++ } else {
++ if ((*qsv_config_context)->io_pattern !=
++ MFX_IOPATTERN_OUT_OPAQUE_MEMORY
++ && (*qsv_config_context)->io_pattern !=
++ MFX_IOPATTERN_OUT_SYSTEM_MEMORY) {
++ av_log_missing_feature( avctx,"Only MFX_IOPATTERN_OUT_OPAQUE_MEMORY and MFX_IOPATTERN_OUT_SYSTEM_MEMORY are currently supported\n",0);
++ return AVERROR_PATCHWELCOME;
++ }
++ }
++
++ qsv->qsv_config = avctx->hwaccel_context;
++
++ av_qsv_add_context_usage(qsv,
++ HAVE_THREADS
++ ? (*qsv_config_context)->usage_threaded :
++ HAVE_THREADS);
++
++ // allocation of p_syncp and p_surfaces inside of ff_qsv_dec_init
++ return ff_qsv_dec_init(avctx);
++}
++
++static av_cold int qsv_decode_end(AVCodecContext * avctx)
++{
++ mfxStatus sts = MFX_ERR_NONE;
++ av_qsv_context *qsv = avctx->priv_data;
++ av_qsv_config *qsv_config_context = avctx->hwaccel_context;
++
++ if (qsv) {
++ av_qsv_space *qsv_decode = qsv->dec_space;
++ if (qsv_decode && qsv_decode->is_init_done) {
++ // todo: change to AV_LOG_INFO
++ av_log(avctx, AV_LOG_QUIET,
++ "qsv_decode report done, max_surfaces: %u/%u , max_syncs: %u/%u\n",
++ qsv_decode->surface_num_max_used,
++ qsv_decode->surface_num, qsv_decode->sync_num_max_used,
++ qsv_decode->sync_num);
++ }
++
++ if (qsv_config_context
++ && qsv_config_context->io_pattern ==
++ MFX_IOPATTERN_OUT_SYSTEM_MEMORY) {
++ if (qsv_config_context->allocators) {
++ sts =
++ qsv_config_context->allocators->
++ frame_alloc.Free(qsv_config_context->allocators,
++ &qsv_decode->response);
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++ } else {
++ av_log(avctx, AV_LOG_FATAL,
++ "No QSV allocators found for clean up\n");
++ }
++ }
++ // closing the own resources
++ av_freep(&qsv_decode->p_buf);
++
++ for (int i = 0; i < qsv_decode->surface_num; i++) {
++ av_freep(&qsv_decode->p_surfaces[i]);
++ }
++ qsv_decode->surface_num = 0;
++
++ if( qsv_decode->p_ext_param_num || qsv_decode->p_ext_params )
++ av_freep(&qsv_decode->p_ext_params);
++ qsv_decode->p_ext_param_num = 0;
++
++ for (int i = 0; i < qsv_decode->sync_num; i++) {
++ av_freep(&qsv_decode->p_syncp[i]->p_sync);
++ av_freep(&qsv_decode->p_syncp[i]);
++ }
++ qsv_decode->sync_num = 0;
++ qsv_decode->is_init_done = 0;
++
++ av_freep(&qsv->dec_space);
++
++ // closing commong stuff
++ av_qsv_context_clean(qsv);
++ }
++
++ return 0;
++}
++
++static int qsv_decode_frame(AVCodecContext * avctx, void *data,
++ int *data_size, AVPacket * avpkt)
++{
++ mfxStatus sts = MFX_ERR_NONE;
++ av_qsv_context *qsv = avctx->priv_data;
++ av_qsv_space *qsv_decode;
++ av_qsv_config *qsv_config_context = avctx->hwaccel_context;
++ int *got_picture_ptr = data_size;
++ int ret_value = 1;
++ uint8_t *current_position = avpkt->data;
++ int current_size = avpkt->size;
++ int frame_processed = 0;
++ size_t frame_length = 0;
++ int surface_idx = 0;
++ int extra_data_workaround = 0;
++
++ int sync_idx = 0;
++ int current_nal_size;
++ unsigned char nal_type;
++ av_qsv_stage *new_stage = 0;
++ mfxBitstream *input_bs = NULL;
++ size_t current_offset = 2;
++ av_qsv_list *qsv_atom = 0;
++ av_qsv_list *pipe = 0;
++
++ AVFrame *picture = (AVFrame *) data;
++
++ *got_picture_ptr = 0;
++
++ qsv = avctx->priv_data;
++ if(!qsv){
++ extra_data_workaround = !avctx->extradata_size;
++ if(extra_data_workaround){
++ avctx->extradata = avpkt->data;
++ avctx->extradata_size = avpkt->size;
++ }
++ sts = ff_qsv_decode_init(avctx);
++ qsv = avctx->priv_data;
++ if(extra_data_workaround){
++ avctx->extradata = 0;
++ avctx->extradata_size = 0;
++ }
++ if(sts<0){
++ ff_qsv_dec_init_clean(avctx);
++ *got_picture_ptr = 0;
++ return sts;
++ }
++ }
++ qsv_decode = qsv->dec_space;
++
++ if (qsv_decode->bs.DataOffset + qsv_decode->bs.DataLength +
++ current_size > qsv_decode->bs.MaxLength) {
++ memmove(&qsv_decode->bs.Data[0],
++ qsv_decode->bs.Data + qsv_decode->bs.DataOffset,
++ qsv_decode->bs.DataLength);
++ qsv_decode->bs.DataOffset = 0;
++ }
++
++ if (current_size) {
++ if(qsv->is_anex == ANEX_UNKNOWN){
++ if (ff_qsv_nal_find_start_code(current_position, current_size) && current_position == avpkt->data)
++ qsv->is_anex = ANEX_PREFIX;
++ else
++ qsv->is_anex = ANEX_NO_PREFIX;
++ }
++ if (qsv->is_anex == ANEX_PREFIX){
++ memcpy(&qsv_decode->bs.Data[0] +
++ qsv_decode->bs.DataLength +
++ qsv_decode->bs.DataOffset,
++ avpkt->data,
++ avpkt->size);
++ qsv_decode->bs.DataLength += avpkt->size;
++ frame_length += avpkt->size;
++ }
++ else
++ while (current_offset <= current_size) {
++ current_nal_size =
++ ((unsigned char) current_position[current_offset - 2] << 24 |
++ (unsigned char) current_position[current_offset - 1] << 16 |
++ (unsigned char) current_position[current_offset] << 8 |
++ (unsigned char) current_position[current_offset + 1]) - 1;
++ nal_type =
++ (unsigned char) current_position[current_offset + 2] & 0x1F;
++ {
++ frame_length += current_nal_size;
++ memcpy(&qsv_decode->bs.Data[0] +
++ qsv_decode->bs.DataLength +
++ qsv_decode->bs.DataOffset, ff_prefix_code,
++ sizeof(ff_prefix_code));
++ qsv_decode->bs.DataLength += sizeof(ff_prefix_code);
++ memcpy(&qsv_decode->bs.Data[0] +
++ qsv_decode->bs.DataLength +
++ qsv_decode->bs.DataOffset,
++ &current_position[current_offset + 2],
++ current_nal_size + 1);
++ qsv_decode->bs.DataLength += current_nal_size + 1;
++ }
++ current_offset += current_nal_size + 5;
++ }
++
++ if (qsv_decode->bs.DataLength > qsv_decode->bs.MaxLength) {
++ av_log(avctx, AV_LOG_FATAL, "DataLength > MaxLength\n");
++ return -1;
++ }
++ }
++
++ if (frame_length || current_size == 0) {
++
++ qsv_decode->bs.TimeStamp = avpkt->pts;
++
++ //not a drain
++ if ((current_size || qsv_decode->bs.DataLength))
++ av_qsv_dts_ordered_insert(qsv, 0, 0, qsv_decode->bs.TimeStamp, 0);
++
++ sts = MFX_ERR_NONE;
++ // ignore warnings, where warnings >0 , and not error codes <0
++ while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_SURFACE == sts
++ || MFX_WRN_DEVICE_BUSY == sts) {
++
++ if (MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE == sts) {
++ surface_idx =
++ av_qsv_get_free_surface(qsv_decode, qsv,
++ &qsv_decode->request[0].Info,
++ QSV_PART_ANY);
++
++ if (surface_idx == -1) {
++ *got_picture_ptr = 0;
++ return 0;
++ }
++ }
++
++ if (MFX_WRN_DEVICE_BUSY == sts)
++ av_qsv_sleep(10);
++
++ sync_idx = av_qsv_get_free_sync(qsv_decode, qsv);
++
++ if (sync_idx == -1) {
++ *got_picture_ptr = 0;
++ return 0;
++ }
++ new_stage = av_qsv_stage_init();
++ input_bs = NULL;
++ // if to drain last ones
++ if (current_size || qsv_decode->bs.DataLength)
++ input_bs = &qsv_decode->bs;
++ // Decode a frame asynchronously (returns immediately)
++ // very first IDR / SLICE should be with SPS/PPS
++ sts = MFXVideoDECODE_DecodeFrameAsync(qsv->mfx_session, input_bs,
++ qsv_decode->p_surfaces
++ [surface_idx],
++ &new_stage->out.p_surface,
++ qsv_decode->p_syncp[sync_idx]->p_sync);
++
++ new_stage->out.sync = qsv_decode->p_syncp[sync_idx];
++ // have some results
++ if (MFX_ERR_NONE <= sts && MFX_WRN_DEVICE_BUSY != sts &&
++ MFX_WRN_VIDEO_PARAM_CHANGED != sts) {
++
++ ff_qsv_atomic_inc(&(new_stage->out.p_surface->Data.Locked));
++
++ new_stage->type = AV_QSV_DECODE;
++ new_stage->in.p_bs = input_bs;
++ new_stage->in.p_surface = qsv_decode->p_surfaces[surface_idx];
++
++ pipe = av_qsv_list_init(HAVE_THREADS ? qsv_config_context->usage_threaded : HAVE_THREADS);
++ av_qsv_add_stagee(&pipe, new_stage,
++ HAVE_THREADS ?
++ qsv_config_context->usage_threaded :
++ HAVE_THREADS);
++
++ av_qsv_list_add(qsv->pipes, pipe);
++ qsv_atom = pipe;
++
++ // usage for forced decode sync and results, can be avoided if sync done by next stage
++ // also note wait time for Sync and possible usage with MFX_WRN_IN_EXECUTION check
++ if (qsv_config_context->sync_need) {
++ sts =
++ MFXVideoCORE_SyncOperation(qsv->mfx_session,
++ qsv_decode->p_syncp[sync_idx]->p_sync,
++ qsv_config_context->sync_need);
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++
++ // no need to wait more -> force off
++ ff_qsv_atomic_dec(&qsv_decode->p_syncp[sync_idx]->in_use);
++ new_stage->out.sync = 0;
++ }
++
++ sts = MFX_ERR_NONE;
++ break;
++ }
++ av_qsv_stage_clean(&new_stage);
++
++ /*
++ Can be because of:
++ - runtime situation:
++ - drain procedure:
++ At the end of the bitstream, the application continuously calls the MFXVideoDECODE_DecodeFrameAsync function with a
++ NULL bitstream pointer to drain any remaining frames cached within the Intel
++ Media SDK decoder, until the function returns MFX_ERR_MORE_DATA.
++ */
++ if (MFX_ERR_MORE_DATA == sts) {
++ // not a drain
++ if (current_size) {
++ *got_picture_ptr = 0;
++ return avpkt->size;
++ }
++ // drain
++ break;
++ }
++ if (MFX_ERR_MORE_SURFACE == sts ){
++ continue;
++ }
++
++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
++ }
++
++ frame_processed = 1;
++ }
++
++ if (frame_processed) {
++
++ if (current_size) {
++ *got_picture_ptr = 1;
++ ret_value = avpkt->size;
++ } else {
++ if (MFX_ERR_MORE_DATA != sts) {
++ *got_picture_ptr = 1;
++ ret_value = avpkt->size;
++ } else {
++ *got_picture_ptr = 0;
++ return 0;
++ }
++ }
++
++ picture->pkt_pts = new_stage->out.p_surface->Data.TimeStamp;
++ picture->pts = new_stage->out.p_surface->Data.TimeStamp;
++
++ picture->repeat_pict = (qsv_decode->m_mfxVideoParam.mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_FIELD_REPEATED);
++ picture->interlaced_frame = !(qsv_decode->m_mfxVideoParam.mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_PROGRESSIVE);
++ picture->top_field_first = (qsv_decode->m_mfxVideoParam.mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_FIELD_TFF);
++
++ // since we do not know it yet from MSDK, let's do just a simple way for now
++ picture->key_frame = (avctx->frame_number == 0) ? 1 : 0;
++
++ if (qsv_decode->m_mfxVideoParam.IOPattern == MFX_IOPATTERN_OUT_SYSTEM_MEMORY) {
++ picture->data[0] = new_stage->out.p_surface->Data.Y;
++ picture->data[1] = new_stage->out.p_surface->Data.VU;
++ picture->linesize[0] = new_stage->out.p_surface->Info.Width;
++ picture->linesize[1] = new_stage->out.p_surface->Info.Width;
++ } else {
++ picture->data[0] = 0;
++ picture->data[1] = 0;
++ picture->linesize[0] = 0;
++ picture->linesize[1] = 0;
++ }
++
++ picture->data[2] = qsv_atom;
++ picture->linesize[2] = 0;
++ }
++
++ return ret_value;
++}
++
++// Will be called when seeking
++static void qsv_flush_dpb(AVCodecContext * avctx)
++{
++ av_qsv_context *qsv = avctx->priv_data;
++ av_qsv_space *qsv_decode = qsv->dec_space;
++
++ qsv_decode->bs.DataOffset = 0;
++ qsv_decode->bs.DataLength = 0;
++ qsv_decode->bs.MaxLength = qsv_decode->p_buf_max_size;
++}
++
++
++mfxStatus ff_qsv_mem_frame_alloc(mfxHDL pthis,
++ mfxFrameAllocRequest * request,
++ mfxFrameAllocResponse * response)
++{
++ mfxStatus sts = MFX_ERR_NONE;
++
++ mfxU32 numAllocated = 0;
++
++ mfxU32 width = AV_QSV_ALIGN32(request->Info.Width);
++ mfxU32 height = AV_QSV_ALIGN32(request->Info.Height);
++ mfxU32 nbytes;
++
++ av_qsv_allocators_space *this_alloc = (av_qsv_allocators_space *) pthis;
++ av_qsv_alloc_frame *fs;
++
++ if (!this_alloc->space)
++ return MFX_ERR_NOT_INITIALIZED;
++
++ switch (request->Info.FourCC) {
++ case MFX_FOURCC_YV12:
++ case MFX_FOURCC_NV12:
++ nbytes =
++ width * height + (width >> 1) * (height >> 1) +
++ (width >> 1) * (height >> 1);
++ break;
++ case MFX_FOURCC_RGB3:
++ nbytes = width * height + width * height + width * height;
++ break;
++ case MFX_FOURCC_RGB4:
++ nbytes =
++ width * height + width * height + width * height +
++ width * height;
++ break;
++ case MFX_FOURCC_YUY2:
++ nbytes =
++ width * height + (width >> 1) * (height) +
++ (width >> 1) * (height);
++ break;
++ default:
++ return MFX_ERR_UNSUPPORTED;
++ }
++
++ this_alloc->space->mids =
++ av_malloc(sizeof(mfxMemId) * request->NumFrameSuggested);
++ if (!this_alloc->space->mids)
++ return MFX_ERR_MEMORY_ALLOC;
++
++ // allocate frames
++ for (numAllocated = 0; numAllocated < request->NumFrameSuggested;
++ numAllocated++) {
++ sts =
++ this_alloc->buffer_alloc.Alloc(this_alloc->buffer_alloc.pthis,
++ nbytes +
++ AV_QSV_ALIGN32(sizeof
++ (av_qsv_alloc_frame)),
++ request->Type,
++ &(this_alloc->
++ space->mids[numAllocated]));
++
++ if (MFX_ERR_NONE != sts)
++ break;
++
++ sts =
++ this_alloc->buffer_alloc.Lock(this_alloc->buffer_alloc.pthis,
++ this_alloc->
++ space->mids[numAllocated],
++ (mfxU8 **) & fs);
++
++ if (MFX_ERR_NONE != sts)
++ break;
++
++ fs->id = AV_QSV_ID_FRAME;
++ fs->info = request->Info;
++ this_alloc->buffer_alloc.Unlock(this_alloc->buffer_alloc.pthis,
++ this_alloc->
++ space->mids[numAllocated]);
++ }
++
++ // check the number of allocated frames
++ if (numAllocated < request->NumFrameMin)
++ return MFX_ERR_MEMORY_ALLOC;
++
++ response->NumFrameActual = (mfxU16) numAllocated;
++ response->mids = this_alloc->space->mids;
++
++ return MFX_ERR_NONE;
++}
++
++mfxStatus ff_qsv_mem_frame_lock(mfxHDL pthis, mfxMemId mid,
++ mfxFrameData * ptr)
++{
++ mfxStatus sts = MFX_ERR_NONE;
++ av_qsv_alloc_frame *fs = 0;
++ mfxU16 width;
++ mfxU16 height;
++
++ av_qsv_allocators_space *this_alloc = (av_qsv_allocators_space *) pthis;
++
++ if (!this_alloc->space)
++ return MFX_ERR_NOT_INITIALIZED;
++ if (!ptr)
++ return MFX_ERR_NULL_PTR;
++
++
++ sts =
++ this_alloc->buffer_alloc.Lock(this_alloc->buffer_alloc.pthis, mid,
++ (mfxU8 **) & fs);
++
++ if (MFX_ERR_NONE != sts)
++ return sts;
++
++ if (AV_QSV_ID_FRAME != fs->id) {
++ this_alloc->buffer_alloc.Unlock(this_alloc->buffer_alloc.pthis,
++ mid);
++ return MFX_ERR_INVALID_HANDLE;
++ }
++
++ width = (mfxU16) AV_QSV_ALIGN32(fs->info.Width);
++ height = (mfxU16) AV_QSV_ALIGN32(fs->info.Height);
++ ptr->B = ptr->Y =
++ (mfxU8 *) fs + AV_QSV_ALIGN32(sizeof(av_qsv_allocators_space));
++
++ switch (fs->info.FourCC) {
++ case MFX_FOURCC_NV12:
++ ptr->U = ptr->Y + width * height;
++ ptr->V = ptr->U + 1;
++ ptr->Pitch = width;
++ break;
++ case MFX_FOURCC_YV12:
++ ptr->V = ptr->Y + width * height;
++ ptr->U = ptr->V + (width >> 1) * (height >> 1);
++ ptr->Pitch = width;
++ break;
++ case MFX_FOURCC_YUY2:
++ ptr->U = ptr->Y + 1;
++ ptr->V = ptr->Y + 3;
++ ptr->Pitch = 2 * width;
++ break;
++ case MFX_FOURCC_RGB3:
++ ptr->G = ptr->B + 1;
++ ptr->R = ptr->B + 2;
++ ptr->Pitch = 3 * width;
++ break;
++ case MFX_FOURCC_RGB4:
++ ptr->G = ptr->B + 1;
++ ptr->R = ptr->B + 2;
++ ptr->A = ptr->B + 3;
++ ptr->Pitch = 4 * width;
++ break;
++ default:
++ return MFX_ERR_UNSUPPORTED;
++ }
++
++ return MFX_ERR_NONE;
++}
++
++mfxStatus ff_qsv_mem_frame_unlock(mfxHDL pthis, mfxMemId mid,
++ mfxFrameData * ptr)
++{
++ mfxStatus sts = MFX_ERR_NONE;
++ av_qsv_allocators_space *this_alloc = (av_qsv_allocators_space *) pthis;
++
++ sts =
++ this_alloc->buffer_alloc.Unlock(this_alloc->buffer_alloc.pthis,
++ mid);
++
++ if (MFX_ERR_NONE != sts)
++ return sts;
++
++ if (NULL != ptr) {
++ ptr->Pitch = 0;
++ ptr->Y = 0;
++ ptr->U = 0;
++ ptr->V = 0;
++ }
++
++ return MFX_ERR_NONE;
++}
++
++mfxStatus ff_qsv_mem_frame_getHDL(mfxHDL pthis, mfxMemId mid,
++ mfxHDL * handle)
++{
++ return MFX_ERR_UNSUPPORTED;
++}
++
++mfxStatus ff_qsv_mem_frame_free(mfxHDL pthis,
++ mfxFrameAllocResponse * response)
++{
++ mfxStatus sts = MFX_ERR_NONE;
++ av_qsv_allocators_space *this_alloc = (av_qsv_allocators_space *) pthis;
++ mfxU32 i;
++
++ if (!response)
++ return MFX_ERR_NULL_PTR;
++
++ if (!this_alloc->space)
++ return MFX_ERR_NOT_INITIALIZED;
++
++ if (response->mids)
++ for (i = 0; i < response->NumFrameActual; i++) {
++ if (response->mids[i]) {
++ sts =
++ this_alloc->buffer_alloc.Free(this_alloc->
++ buffer_alloc.pthis,
++ response->mids[i]);
++ if (MFX_ERR_NONE != sts)
++ return sts;
++ }
++ }
++
++ av_freep(&response->mids);
++
++ return sts;
++}
++
++
++mfxStatus ff_qsv_mem_buffer_alloc(mfxHDL pthis, mfxU32 nbytes, mfxU16 type,
++ mfxMemId * mid)
++{
++ av_qsv_alloc_buffer *bs;
++ mfxU32 header_size;
++ mfxU8 *buffer_ptr;
++
++ if (!mid)
++ return MFX_ERR_NULL_PTR;
++
++ if (0 == (type & MFX_MEMTYPE_SYSTEM_MEMORY))
++ return MFX_ERR_UNSUPPORTED;
++
++ header_size = AV_QSV_ALIGN32(sizeof(av_qsv_alloc_buffer));
++ buffer_ptr = (mfxU8 *) av_malloc(header_size + nbytes);
++
++ if (!buffer_ptr)
++ return MFX_ERR_MEMORY_ALLOC;
++
++ bs = (av_qsv_alloc_buffer *) buffer_ptr;
++ bs->id = AV_QSV_ID_BUFFER;
++ bs->type = type;
++ bs->nbytes = nbytes;
++ *mid = (mfxHDL) bs;
++ return MFX_ERR_NONE;
++}
++
++mfxStatus ff_qsv_mem_buffer_lock(mfxHDL pthis, mfxMemId mid, mfxU8 ** ptr)
++{
++ av_qsv_alloc_buffer *bs;
++
++ if (!ptr)
++ return MFX_ERR_NULL_PTR;
++
++ bs = (av_qsv_alloc_buffer *) mid;
++
++ if (!bs)
++ return MFX_ERR_INVALID_HANDLE;
++ if (AV_QSV_ID_BUFFER != bs->id)
++ return MFX_ERR_INVALID_HANDLE;
++
++ *ptr = (mfxU8 *) bs + AV_QSV_ALIGN32(sizeof(av_qsv_alloc_buffer));
++ return MFX_ERR_NONE;
++}
++
++mfxStatus ff_qsv_mem_buffer_unlock(mfxHDL pthis, mfxMemId mid)
++{
++ av_qsv_alloc_buffer *bs = (av_qsv_alloc_buffer *) mid;
++
++ if (!bs || AV_QSV_ID_BUFFER != bs->id)
++ return MFX_ERR_INVALID_HANDLE;
++
++ return MFX_ERR_NONE;
++}
++
++mfxStatus ff_qsv_mem_buffer_free(mfxHDL pthis, mfxMemId mid)
++{
++ av_qsv_alloc_buffer *bs = (av_qsv_alloc_buffer *) mid;
++ if (!bs || AV_QSV_ID_BUFFER != bs->id)
++ return MFX_ERR_INVALID_HANDLE;
++
++ av_freep(&bs);
++ return MFX_ERR_NONE;
++}
++
++
++AVCodec ff_h264_qsv_decoder = {
++ .name = "h264_qsv",
++ .type = AVMEDIA_TYPE_VIDEO,
++ .id = AV_CODEC_ID_H264,
++ .init = ff_qsv_decode_init,
++ .close = qsv_decode_end,
++ .decode = qsv_decode_frame,
++ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
++ .flush = qsv_flush_dpb,
++ .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / Intel QSV"),
++ .pix_fmts = (const enum PixelFormat[]) {AV_PIX_FMT_QSV_H264,
++ AV_PIX_FMT_NONE},
++};
+diff -Naur ../../libav-v9.6/libavcodec/qsv_h264.h ./libavcodec/qsv_h264.h
+--- ../../libav-v9.6/libavcodec/qsv_h264.h 1970-01-01 01:00:00.000000000 +0100
++++ ./libavcodec/qsv_h264.h 2013-08-19 21:32:01.710244809 +0200
+@@ -0,0 +1,65 @@
++/* ********************************************************************* *\
++
++Copyright (C) 2013 Intel Corporation. All rights reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++- Redistributions of source code must retain the above copyright notice,
++this list of conditions and the following disclaimer.
++- Redistributions in binary form must reproduce the above copyright notice,
++this list of conditions and the following disclaimer in the documentation
++and/or other materials provided with the distribution.
++- Neither the name of Intel Corporation nor the names of its contributors
++may be used to endorse or promote products derived from this software
++without specific prior written permission.
++
++THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR
++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT,
++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++
++\* ********************************************************************* */
++
++#ifndef AVCODEC_QSV_H264_H
++#define AVCODEC_QSV_H264_H
++
++#include "qsv.h"
++
++int ff_qsv_dec_init(AVCodecContext *);
++int ff_qsv_nal_find_start_code(uint8_t * pb, size_t size);
++
++int ff_qsv_dec_init_clean(AVCodecContext *avctx);
++av_cold int ff_qsv_decode_init(AVCodecContext * avctx);
++static av_cold int qsv_decode_end(AVCodecContext * avctx);
++static int qsv_decode_frame(AVCodecContext * avctx, void *data,
++ int *data_size, AVPacket * avpkt);
++static void qsv_flush_dpb(AVCodecContext * avctx);
++
++
++// Default for SYSTEM MEMORY
++// as from MFXFrameAllocator
++mfxStatus ff_qsv_mem_frame_alloc(mfxHDL pthis,
++ mfxFrameAllocRequest * request,
++ mfxFrameAllocResponse * response);
++mfxStatus ff_qsv_mem_frame_lock(mfxHDL pthis, mfxMemId mid,
++ mfxFrameData * ptr);
++mfxStatus ff_qsv_mem_frame_unlock(mfxHDL pthis, mfxMemId mid,
++ mfxFrameData * ptr);
++mfxStatus ff_qsv_mem_frame_getHDL(mfxHDL pthis, mfxMemId mid,
++ mfxHDL * handle);
++mfxStatus ff_qsv_mem_frame_free(mfxHDL pthis,
++ mfxFrameAllocResponse * response);
++// as from mfxBufferAllocator
++mfxStatus ff_qsv_mem_buffer_alloc(mfxHDL pthis, mfxU32 nbytes, mfxU16 type,
++ mfxMemId * mid);
++mfxStatus ff_qsv_mem_buffer_lock(mfxHDL pthis, mfxMemId mid, mfxU8 ** ptr);
++mfxStatus ff_qsv_mem_buffer_unlock(mfxHDL pthis, mfxMemId mid);
++mfxStatus ff_qsv_mem_buffer_free(mfxHDL pthis, mfxMemId mid);
++
++#endif //AVCODEC_QSV_H264_H
+diff -Naur ../../libav-v9.6/libavutil/pixfmt.h ./libavutil/pixfmt.h
+--- ../../libav-v9.6/libavutil/pixfmt.h 2013-05-12 08:39:07.000000000 +0200
++++ ./libavutil/pixfmt.h 2013-08-14 10:48:00.522497405 +0200
+@@ -178,6 +178,7 @@
+ AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian)
+ AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian)
+ AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian)
++ AV_PIX_FMT_QSV_H264, ///< H.264 HW decoding with QSV, data[2] contains qsv_atom information for MFX_IOPATTERN_OUT_OPAQUE_MEMORY, MFX_IOPATTERN_OUT_VIDEO_MEMORY
+ AV_PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
+
+ #if FF_API_PIX_FMT