]> granicus.if.org Git - handbrake/commitdiff
Big merge, QSV to trunk: part 1 (tracked files).
authorRodeo <tdskywalker@gmail.com>
Thu, 22 Aug 2013 20:33:35 +0000 (20:33 +0000)
committerRodeo <tdskywalker@gmail.com>
Thu, 22 Aug 2013 20:33:35 +0000 (20:33 +0000)
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5737 b64f7644-9d1e-0410-96f1-a4d463321fa5

22 files changed:
contrib/ffmpeg/module.defs
libhb/common.c
libhb/common.h
libhb/decavcodec.c
libhb/decmpeg2.c
libhb/encx264.h
libhb/fifo.c
libhb/hb.c
libhb/internal.h
libhb/module.defs
libhb/muxavformat.c
libhb/muxmkv.c
libhb/muxmp4.c
libhb/ports.c
libhb/ports.h
libhb/scan.c
libhb/sync.c
libhb/work.c
make/configure.py
make/include/main.defs
test/module.defs
test/test.c

index fdce86fde8e18ba80d9b6b40869d8e3ca815eba8..6120ff39cd11b71cc7309de7644a7fa5831d15ea 100644 (file)
@@ -1,4 +1,8 @@
+ifeq (1,$(FEATURE.qsv))
+$(eval $(call import.MODULE.defs,FFMPEG,ffmpeg,YASM BZIP2 ZLIB FDKAAC PTHREADW32 LIBMFX))
+else
 $(eval $(call import.MODULE.defs,FFMPEG,ffmpeg,YASM BZIP2 ZLIB FDKAAC))
+endif
 $(eval $(call import.CONTRIB.defs,FFMPEG))
 
 FFMPEG.FETCH.url = http://download.handbrake.fr/handbrake/contrib/libav-v9.6.tar.bz2
@@ -86,6 +90,10 @@ ifeq (none,$(FFMPEG.GCC.O))
        FFMPEG.CONFIGURE.extra += --disable-optimizations
 endif
 
+ifeq (1,$(FEATURE.qsv))
+   FFMPEG.CONFIGURE.extra += --enable-qsv
+endif
+
 ## enable compile verbosity
 FFMPEG.BUILD.extra = V=1
 
index 3eaa941b3d8ec2c4eaccaad50ef4d93ef5a7111e..66f3b0440e14c42d4107e0cf73c13635189874a5 100644 (file)
 #include <ctype.h>
 #include <sys/time.h>
 
-#include "common.h"
-#include "lang.h"
 #include "hb.h"
+#include "lang.h"
+#include "common.h"
+#ifdef USE_QSV
+#include "qsv_common.h"
+#endif
 
 /**********************************************************************
  * Global variables
@@ -191,6 +194,7 @@ hb_encoder_internal_t hb_video_encoders[]  =
     { { "VP3 (Theora)",      "libtheora", HB_VCODEC_THEORA,                       HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_THEORA, },
     // actual encoders
     { { "H.264 (x264)",      "x264",      HB_VCODEC_X264,         HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264,   },
+    { { "H.264 (Intel QSV)", "qsv_h264",  HB_VCODEC_QSV_H264,     HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264,   },
     { { "MPEG-4",            "mpeg4",     HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG4,  },
     { { "MPEG-2",            "mpeg2",     HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG2,  },
     { { "Theora",            "theora",    HB_VCODEC_THEORA,                       HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_THEORA, },
@@ -200,6 +204,11 @@ static int hb_video_encoder_is_enabled(int encoder)
 {
     switch (encoder)
     {
+#ifdef USE_QSV
+        case HB_VCODEC_QSV_H264:
+            return hb_qsv_available();
+#endif
+
         // the following encoders are always enabled
         case HB_VCODEC_X264:
         case HB_VCODEC_THEORA:
@@ -2874,6 +2883,12 @@ static void job_setup( hb_job_t * job, hb_title_t * title )
 
     job->list_attachment = hb_attachment_list_copy( title->list_attachment );
     job->metadata = hb_metadata_copy( title->metadata );
+
+#ifdef USE_QSV
+    job->qsv_enc_info.is_init_done = 0;
+    job->qsv_decode                = title->qsv_decode_support;
+    job->qsv_async_depth           = AV_QSV_ASYNC_DEPTH_DEFAULT;
+#endif
 }
 
 static void job_clean( hb_job_t * job )
@@ -3133,6 +3148,20 @@ hb_filter_object_t * hb_filter_init( int filter_id )
             filter = &hb_filter_rotate;
             break;
 
+#ifdef USE_QSV
+        case HB_FILTER_QSV:
+            filter = &hb_filter_qsv;
+            break;
+
+        case HB_FILTER_QSV_PRE:
+            filter = &hb_filter_qsv_pre;
+            break;
+
+        case HB_FILTER_QSV_POST:
+            filter = &hb_filter_qsv_post;
+            break;
+#endif
+
         default:
             filter = NULL;
             break;
index 5a21eab84bab729ba09c8e7d05abb324bfbccb57..38c97e487265b6e3d3f377f1abd0d362e3e85a82 100644 (file)
@@ -105,6 +105,15 @@ typedef struct hb_lock_s hb_lock_t;
 #include "audio_remap.h"
 #include "libavutil/channel_layout.h"
 
+#ifdef USE_QSV
+
+#ifndef DEBUG_ASSERT
+#define DEBUG_ASSERT(x,y) { if ((x)) { hb_error("ASSERT: %s", y); exit(1); } }
+#endif
+
+#include "libavcodec/qsv.h"
+#endif
+
 hb_list_t * hb_list_init();
 int         hb_list_count( const hb_list_t * );
 void        hb_list_add( hb_list_t *, void * );
@@ -403,12 +412,15 @@ struct hb_job_s
          pass:              0, 1 or 2 (or -1 for scan)
          advanced_opts:     string of extra advanced encoder options
          areBframes:        boolean to note if b-frames are included in advanced_opts */
-#define HB_VCODEC_MASK         0x00000FF
+#define HB_VCODEC_MASK         0x0000FFF
 #define HB_VCODEC_X264         0x0000001
 #define HB_VCODEC_THEORA       0x0000002
 #define HB_VCODEC_FFMPEG_MPEG4 0x0000010
 #define HB_VCODEC_FFMPEG_MPEG2 0x0000020
 #define HB_VCODEC_FFMPEG_MASK  0x00000F0
+#define HB_VCODEC_QSV_H264     0x0000100
+#define HB_VCODEC_QSV_MASK     0x0000F00
+#define HB_VCODEC_H264_MASK    (HB_VCODEC_X264|HB_VCODEC_QSV_H264)
 
     int             vcodec;
     float           vquality;
@@ -500,6 +512,21 @@ struct hb_job_s
     uint32_t        frames_to_skip;     // decode but discard this many frames
                                         //  initially (for frame accurate positioning
                                         //  to non-I frames).
+#ifdef USE_QSV
+    av_qsv_context   *qsv;
+    int               qsv_decode;
+    int               qsv_async_depth;
+    // shared encoding parameters
+    // initialized by the QSV encoder, then used upstream (e.g. by filters) to
+    // configure their output so that it corresponds to what the encoder expects
+    struct
+    {
+        int pic_struct;
+        int align_width;
+        int align_height;
+        int is_init_done;
+    } qsv_enc_info;
+#endif
 
 #ifdef __LIBHB__
     /* Internal data */
@@ -833,6 +860,10 @@ struct hb_title_s
     char        *container_name;
     int         data_rate;
 
+#ifdef USE_QSV
+    int qsv_decode_support;
+#endif
+
     hb_metadata_t *metadata;
 
     hb_list_t * list_chapter;
@@ -929,6 +960,9 @@ typedef struct hb_work_info_s
             int color_prim;
             int color_transfer;
             int color_matrix;
+#ifdef USE_QSV
+            int qsv_decode_support;
+#endif
         };
         struct
         {    // info only valid for audio decoders
@@ -998,6 +1032,7 @@ extern hb_work_object_t hb_dectx3gsub;
 extern hb_work_object_t hb_decssasub;
 extern hb_work_object_t hb_decpgssub;
 extern hb_work_object_t hb_encavcodec;
+extern hb_work_object_t hb_encqsv;
 extern hb_work_object_t hb_encx264;
 extern hb_work_object_t hb_enctheora;
 extern hb_work_object_t hb_deca52;
@@ -1076,8 +1111,11 @@ struct hb_filter_object_s
 
 enum
 {
+    // for QSV - important to have before other filters
+    HB_FILTER_QSV_PRE = 1,
+
     // First, filters that may change the framerate (drop or dup frames)
-    HB_FILTER_DETELECINE = 1,
+    HB_FILTER_DETELECINE,
     HB_FILTER_DECOMB,
     HB_FILTER_DEINTERLACE,
     HB_FILTER_VFR,
@@ -1089,6 +1127,11 @@ enum
     // Finally filters that don't care what order they are in,
     // except that they must be after the above filters
     HB_FILTER_ROTATE,
+
+    // for QSV - important to have as a last one
+    HB_FILTER_QSV_POST,
+    // default MSDK VPP filter
+    HB_FILTER_QSV,
 };
 
 hb_filter_object_t * hb_filter_init( int filter_id );
index 7dcfce90e3e0fb7f1e0f6b1375108872f26dd7a8..4c1972fdfe9a56510aab1633f4a15dba4ac46e30 100644 (file)
 #include "hbffmpeg.h"
 #include "audio_resample.h"
 
+#ifdef USE_QSV
+#include "enc_qsv.h"
+#include "qsv_common.h"
+#endif
+
 static void compute_frame_duration( hb_work_private_t *pv );
 static void flushDelayQueue( hb_work_private_t *pv );
 static int  decavcodecaInit( hb_work_object_t *, hb_job_t * );
@@ -101,8 +106,69 @@ struct hb_work_private_s
     int wait_for_keyframe;
 
     hb_audio_resample_t *resample;
+#ifdef USE_QSV
+    av_qsv_config   qsv_config;
+    int             qsv_decode;
+    const char     *qsv_codec_name;
+#define USE_QSV_PTS_WORKAROUND // work around out-of-order output timestamps
+#ifdef  USE_QSV_PTS_WORKAROUND
+    hb_list_t      *qsv_pts_list;
+#endif
+#endif
 };
 
+#ifdef USE_QSV_PTS_WORKAROUND
+// save/restore PTS if the decoder may not attach the right PTS to the frame
+static void hb_av_add_new_pts(hb_list_t *list, int64_t new_pts)
+{
+    int index = 0;
+    int64_t *cur_item, *new_item;
+    if (list != NULL && new_pts != AV_NOPTS_VALUE)
+    {
+        new_item = malloc(sizeof(int64_t));
+        if (new_item != NULL)
+        {
+            *new_item = new_pts;
+            // sort chronologically
+            for (index = 0; index < hb_list_count(list); index++)
+            {
+                cur_item = hb_list_item(list, index);
+                if (cur_item != NULL)
+                {
+                    if (*cur_item == *new_item)
+                    {
+                        // no duplicates
+                        free(new_item);
+                        return;
+                    }
+                    if (*cur_item > *new_item)
+                    {
+                        // insert here
+                        break;
+                    }
+                }
+            }
+            hb_list_insert(list, index, new_item);
+        }
+    }
+}
+static int64_t hb_av_pop_next_pts(hb_list_t *list)
+{
+    int64_t *item, next_pts = AV_NOPTS_VALUE;
+    if (list != NULL && hb_list_count(list) > 0)
+    {
+        item = hb_list_item(list, 0);
+        if (item != NULL)
+        {
+            next_pts = *item;
+            hb_list_rem(list, item);
+            free(item);
+        }
+    }
+    return next_pts;
+}
+#endif
+
 static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size, int64_t pts );
 static hb_buffer_t *link_buf_list( hb_work_private_t *pv );
 
@@ -285,7 +351,12 @@ static void closePrivData( hb_work_private_t ** ppv )
         }
         if ( pv->context && pv->context->codec )
         {
-            hb_avcodec_close( pv->context );
+#ifdef USE_QSV
+            if (!pv->qsv_decode)
+#endif
+            {
+                hb_avcodec_close(pv->context);
+            }
         }
         if ( pv->context )
         {
@@ -297,6 +368,19 @@ static void closePrivData( hb_work_private_t ** ppv )
             hb_list_empty( &pv->list );
         }
         hb_audio_resample_free(pv->resample);
+#ifdef USE_QSV_PTS_WORKAROUND
+        if (pv->qsv_decode && pv->qsv_pts_list != NULL)
+
+        {
+            while (hb_list_count(pv->qsv_pts_list) > 0)
+            {
+                int64_t *item = hb_list_item(pv->qsv_pts_list, 0);
+                hb_list_rem(pv->qsv_pts_list, item);
+                free(item);
+            }
+            hb_list_close(&pv->qsv_pts_list);
+        }
+#endif
         free( pv );
     }
     *ppv = NULL;
@@ -593,6 +677,17 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame )
         h =  pv->job->title->height;
     }
     hb_buffer_t *buf = hb_video_buffer_init( w, h );
+
+#ifdef USE_QSV
+    // no need to copy the frame data when decoding with QSV to opaque memory
+    if (pv->qsv_decode &&
+        pv->qsv_config.io_pattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY)
+    {
+        buf->qsv_details.qsv_atom = frame->data[2];
+        return buf;
+    }
+#endif
+
     uint8_t *dst = buf->data;
 
     if (context->pix_fmt != AV_PIX_FMT_YUV420P || w != context->width ||
@@ -795,10 +890,42 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
         avp.flags |= AV_PKT_FLAG_KEY;
     }
 
+#ifdef USE_QSV_PTS_WORKAROUND
+    /*
+     * The MediaSDK decoder will return decoded frames in the correct order,
+     * but *sometimes* with the incorrect timestamp assigned to them.
+     *
+     * We work around it by saving the input timestamps (in chronological order)
+     * and restoring them after decoding.
+     */
+    if (pv->qsv_decode && avp.data != NULL)
+    {
+        hb_av_add_new_pts(pv->qsv_pts_list, avp.pts);
+    }
+#endif
+
     if ( avcodec_decode_video2( pv->context, &frame, &got_picture, &avp ) < 0 )
     {
         ++pv->decode_errors;
     }
+
+#ifdef USE_QSV
+    if (pv->qsv_decode && pv->job->qsv == NULL && pv->video_codec_opened > 0)
+    {
+        // this is quite late, but we can't be certain that the QSV context is
+        // available until after we call avcodec_decode_video2() at least once
+        pv->job->qsv = pv->context->priv_data;
+    }
+#endif
+
+#ifdef USE_QSV_PTS_WORKAROUND
+    if (pv->qsv_decode && got_picture)
+    {
+        // we got a decoded frame, restore the lowest available PTS
+        frame.pkt_pts = hb_av_pop_next_pts(pv->qsv_pts_list);
+    }
+#endif
+
     if ( global_verbosity_level <= 1 )
     {
         av_log_set_level( oldlevel );
@@ -998,12 +1125,23 @@ static void decodeVideo( hb_work_object_t *w, uint8_t *data, int size, int seque
     } while ( pos < size );
 
     /* the stuff above flushed the parser, now flush the decoder */
-    if ( size <= 0 )
+    if (size <= 0)
     {
-        while ( decodeFrame( w, NULL, 0, sequence, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0 ) )
+        while (decodeFrame(w, NULL, 0, sequence, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0))
         {
+            continue;
         }
-        flushDelayQueue( pv );
+#ifdef USE_QSV
+        if (pv->qsv_decode)
+        {
+            // flush a second time
+            while (decodeFrame(w, NULL, 0, sequence, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0))
+            {
+                continue;
+            }
+        }
+#endif
+        flushDelayQueue(pv);
     }
 }
 
@@ -1045,14 +1183,52 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
         pv->title = w->title;
     pv->list = hb_list_init();
 
+#ifdef USE_QSV
+    if (hb_qsv_decode_is_enabled(job))
+    {
+        // setup the QSV configuration
+        pv->qsv_config.impl_requested     = MFX_IMPL_AUTO_ANY|MFX_IMPL_VIA_ANY;
+        pv->qsv_config.io_pattern         = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
+        pv->qsv_config.async_depth        = job->qsv_async_depth;
+        pv->qsv_config.sync_need          =  0;
+        pv->qsv_config.usage_threaded     =  1;
+        pv->qsv_config.additional_buffers = 64; // FIFO_LARGE
+        if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+        {
+            // more surfaces may be needed for the lookahead
+            pv->qsv_config.additional_buffers = 160;
+        }
+        pv->qsv_codec_name = hb_qsv_decode_get_codec_name(w->codec_param);
+        pv->qsv_decode     = 1;
+    }
+    else
+    {
+        pv->qsv_decode = 0;
+    }
+#endif
+
     if( pv->job && pv->job->title && !pv->job->title->has_resolution_change )
     {
         pv->threads = HB_FFMPEG_THREADS_AUTO;
     }
+
     if ( pv->title->opaque_priv )
     {
         AVFormatContext *ic = (AVFormatContext*)pv->title->opaque_priv;
-        AVCodec *codec = avcodec_find_decoder( w->codec_param );
+
+        AVCodec *codec = NULL;
+
+#ifdef USE_QSV
+        if (pv->qsv_decode)
+        {
+            codec = avcodec_find_decoder_by_name(pv->qsv_codec_name);
+        }
+        else
+#endif
+        {
+            codec = avcodec_find_decoder(w->codec_param);
+        }
+
         if ( codec == NULL )
         {
             hb_log( "decavcodecvInit: failed to find codec for id (%d)", w->codec_param );
@@ -1064,6 +1240,17 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
         pv->context->err_recognition = AV_EF_CRCCHECK;
         pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK;
 
+#ifdef USE_QSV
+        if (pv->qsv_decode)
+        {
+#ifdef USE_QSV_PTS_WORKAROUND
+            pv->qsv_pts_list = hb_list_init();
+#endif
+            // set the QSV configuration before opening the decoder
+            pv->context->hwaccel_context = &pv->qsv_config;
+        }
+#endif
+
         if ( hb_avcodec_open( pv->context, codec, NULL, pv->threads ) )
         {
             hb_log( "decavcodecvInit: avcodec_open failed" );
@@ -1080,7 +1267,20 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
     }
     else
     {
-        AVCodec *codec = avcodec_find_decoder( w->codec_param );
+        AVCodec *codec = NULL;
+
+#ifdef USE_QSV
+        if (pv->qsv_decode)
+        {
+            codec = avcodec_find_decoder_by_name(pv->qsv_codec_name);
+        }
+        else
+#endif
+        {
+            codec = avcodec_find_decoder(w->codec_param);
+        }
+
+
         pv->parser = av_parser_init( w->codec_param );
         pv->context = avcodec_alloc_context3( codec );
         pv->context->workaround_bugs = FF_BUG_AUTODETECT;
@@ -1207,7 +1407,19 @@ static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
     // first frame because of M$ VC1 braindamage).
     if ( !pv->video_codec_opened )
     {
-        AVCodec *codec = avcodec_find_decoder( w->codec_param );
+
+        AVCodec *codec = NULL;
+#ifdef USE_QSV
+        if (pv->qsv_decode)
+        {
+            codec = avcodec_find_decoder_by_name(pv->qsv_codec_name);
+        }
+        else
+#endif
+        {
+            codec = avcodec_find_decoder(w->codec_param);
+        }
+
         if ( codec == NULL )
         {
             hb_log( "decavcodecvWork: failed to find codec for id (%d)", w->codec_param );
@@ -1231,6 +1443,18 @@ static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
             hb_buffer_close( &in );
             return HB_WORK_OK;
         }
+
+#ifdef USE_QSV
+        if (pv->qsv_decode)
+        {
+#ifdef USE_QSV_PTS_WORKAROUND
+            pv->qsv_pts_list = hb_list_init();
+#endif
+            // set the QSV configuration before opening the decoder
+            pv->context->hwaccel_context = &pv->qsv_config;
+        }
+#endif
+
         // disable threaded decoding for scan, can cause crashes
         if ( hb_avcodec_open( pv->context, codec, NULL, pv->threads ) )
         {
@@ -1444,6 +1668,11 @@ static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
         }
     }
 
+#ifdef USE_QSV
+    info->qsv_decode_support = hb_qsv_decode_is_supported(pv->context->codec_id,
+                                                          pv->context->pix_fmt);
+#endif
+
     return 1;
 }
 
index 8844a09af89c02daa3bc820364c98f6204d27223..2a186295d8e036ba704237d461959a9b6eccc503 100644 (file)
@@ -911,6 +911,10 @@ static int decmpeg2Info( hb_work_object_t *w, hb_work_info_t *info )
         info->level = m->info->sequence->profile_level_id & 0xf;
         info->name = "mpeg2";
 
+#ifdef USE_QSV
+        info->qsv_decode_support = 0;
+#endif
+
         if( pv->libmpeg2->info->sequence->flags & SEQ_FLAG_COLOUR_DESCRIPTION )
         {
             switch( pv->libmpeg2->info->sequence->colour_primaries )
index b0ff8b9ca31add4f033fcbfb8bda096968b6b456..63fa1e04a325c552292a24fef7e20790b5286946 100644 (file)
@@ -8,10 +8,7 @@
  */
 
 #include "x264.h"
-
-static const char * const hb_h264_profile_names[] = { "auto", "high", "main", "baseline", NULL, };
-static const char * const   hb_h264_level_names[] = { "auto", "1.0", "1b", "1.1", "1.2", "1.3", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "4.0", "4.1", "4.2", "5.0", "5.1", "5.2",  NULL, };
-static const int    const  hb_h264_level_values[] = {     -1,    10,    9,    11,    12,    13,    20,    21,    22,    30,    31,    32,    40,    41,    42,    50,    51,    52,     0, };
+#include "h264_common.h"
 
 /* x264 preferred option names (left) and synonyms (right).
  * The "preferred" names match names used in x264's param2string function more
index a32242c0377efd5aa81a576e2f5bb15d264f4429..be69616f1aca6cc31a8997dfae33b67e65b747ff 100644 (file)
@@ -389,6 +389,10 @@ hb_buffer_t * hb_buffer_dup( const hb_buffer_t * src )
             hb_buffer_init_planes( buf );
     }
 
+#ifdef USE_QSV
+    memcpy(&buf->qsv_details, &src->qsv_details, sizeof(src->qsv_details));
+#endif
+
     return buf;
 }
 
@@ -412,7 +416,7 @@ int hb_buffer_copy(hb_buffer_t * dst, const hb_buffer_t * src)
 static void hb_buffer_init_planes_internal( hb_buffer_t * b, uint8_t * has_plane )
 {
     uint8_t * plane = b->data;
-    int p, tot = 0;
+    int p;
 
     for( p = 0; p < 4; p++ )
     {
@@ -425,7 +429,6 @@ static void hb_buffer_init_planes_internal( hb_buffer_t * b, uint8_t * has_plane
             b->plane[p].height = hb_image_height( b->f.fmt, b->f.height, p );
             b->plane[p].size   = b->plane[p].stride * b->plane[p].height_stride;
             plane += b->plane[p].size;
-            tot += b->plane[p].size;
         }
     }
 }
@@ -508,6 +511,7 @@ void hb_video_buffer_realloc( hb_buffer_t * buf, int width, int height )
 
     buf->f.width = width;
     buf->f.height = height;
+    buf->size = size;
 
     hb_buffer_init_planes_internal( buf, has_plane );
 }
@@ -570,6 +574,11 @@ void hb_buffer_move_subs( hb_buffer_t * dst, hb_buffer_t * src )
     // Note that dst takes ownership of the subtitles
     dst->sub       = src->sub;
     src->sub       = NULL;
+
+#ifdef USE_QSV
+       memcpy(&dst->qsv_details, &src->qsv_details, sizeof(src->qsv_details));
+#endif
+
 }
 
 hb_fifo_t * hb_fifo_init( int capacity, int thresh )
index 2a9ed10703e25af016254057b939cb1cd8049642..629b2e3a3ca04d85e2964aef9e3a24c1ed0bfe4a 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 
+#ifdef USE_QSV
+#include "qsv_common.h"
+#endif
+
 #if defined( SYS_MINGW )
 #include <io.h>
 #if defined( PTW32_STATIC_LIB )
@@ -436,6 +440,11 @@ hb_handle_t * hb_init( int verbose, int update_check )
 
     h->interjob = calloc( sizeof( hb_interjob_t ), 1 );
 
+#ifdef USE_QSV
+    /* Intel Quick Sync Video */
+    hb_qsv_info_print();
+#endif
+
     /* Start library thread */
     hb_log( "hb_init: starting libhb thread" );
     h->die         = 0;
@@ -1629,6 +1638,15 @@ int hb_global_init()
         return -1;
     }
 
+#ifdef USE_QSV
+    result = hb_qsv_info_init();
+    if (result < 0)
+    {
+        hb_error("hb_qsv_info_init failed!");
+        return -1;
+    }
+#endif
+
     /* libavcodec */
     hb_avcodec_init();
 
@@ -1663,6 +1681,9 @@ int hb_global_init()
     hb_register(&hb_enctheora);
     hb_register(&hb_encvorbis);
     hb_register(&hb_encx264);
+#ifdef USE_QSV
+    hb_register(&hb_encqsv);
+#endif
     
     hb_common_global_init();
 
index d93119fb08a4c1381064c409a7a20bc177c664de..86878eb17fe4ca6408a278c8482a1404fcff35ab 100644 (file)
@@ -115,6 +115,12 @@ struct hb_buffer_s
         int           size;
     } plane[4]; // 3 Color components + alpha
 
+    struct qsv
+    {
+        void *qsv_atom;
+        void *filter_details;
+    } qsv_details;
+
     // PICTURESUB subtitle packets:
 
     // Video packets (after processing by the hb_sync_video work-object):
@@ -404,6 +410,7 @@ enum
     WORK_ENCVOBSUB,
     WORK_RENDER,
     WORK_ENCAVCODEC,
+    WORK_ENCQSV,
     WORK_ENCX264,
     WORK_ENCTHEORA,
     WORK_DECA52,
@@ -431,6 +438,12 @@ extern hb_filter_object_t hb_filter_crop_scale;
 extern hb_filter_object_t hb_filter_render_sub;
 extern hb_filter_object_t hb_filter_vfr;
 
+#ifdef USE_QSV
+extern hb_filter_object_t hb_filter_qsv;
+extern hb_filter_object_t hb_filter_qsv_pre;
+extern hb_filter_object_t hb_filter_qsv_post;
+#endif
+
 // Picture flags used by filters
 #ifndef PIC_FLAG_REPEAT_FIRST_FIELD
 #define PIC_FLAG_REPEAT_FIRST_FIELD 256
index afaf6ffd124205e635126759b929bb0d95ddc2a9..b161f4c7f7b45bc795a65fc2daabad272d71e206 100644 (file)
@@ -1,6 +1,6 @@
 __deps__ := A52DEC BZIP2 FAAC FFMPEG FONTCONFIG FREETYPE LAME LIBASS LIBDCA \
     LIBDVDREAD LIBDVDNAV LIBICONV LIBMKV LIBOGG LIBSAMPLERATE LIBTHEORA LIBVORBIS LIBXML2 \
-    MP4V2 MPEG2DEC PTHREADW32 X264 ZLIB LIBBLURAY FDKAAC
+    MP4V2 MPEG2DEC PTHREADW32 X264 ZLIB LIBBLURAY FDKAAC LIBMFX
 
 $(eval $(call import.MODULE.defs,LIBHB,libhb,$(__deps__)))
 $(eval $(call import.GCC,LIBHB))
@@ -13,7 +13,12 @@ LIBHB.build/ = $(BUILD/)libhb/
 LIBHB.m4.in  = $(wildcard $(LIBHB.src/)*.m4)
 LIBHB.m4.out = $(patsubst $(LIBHB.src/)%.m4,$(LIBHB.build/)%,$(LIBHB.m4.in))
 
+ifeq (1,$(FEATURE.qsv))
 LIBHB.c   = $(wildcard $(LIBHB.src/)*.c)
+else
+LIBHB.c   = $(filter-out $(wildcard $(LIBHB.src/)*qsv*.c), $(wildcard $(LIBHB.src/)*.c))
+endif
+
 LIBHB.c.o = $(patsubst $(SRC/)%.c,$(BUILD/)%.o,$(LIBHB.c))
 LIBHB.d   = $(LIBHB.m4.out) $(LIBHB.h.out) \
     $(foreach n,$(LIBHB.prerequisites),$($n.INSTALL.target) )
@@ -74,6 +79,10 @@ else
     LIBHB.platform.D = SYS_UNKNOWN
 endif
 
+ifeq (1,$(FEATURE.qsv))    
+    LIBHB.GCC.D += USE_QSV HAVE_THREADS=1
+endif  
+
 ## required for <libdvdread/*.h>
 ifneq (,$(filter $(BUILD.arch),ppc ppc64))
        LIBHB.GCC.D += WORDS_BIGENDIAN
@@ -123,6 +132,10 @@ ifeq (1,$(FEATURE.faac))
 LIBHB.dll.libs += $(CONTRIB.build/)lib/libfaac.a
 endif
 
+ifeq (1,$(FEATURE.qsv))
+LIBHB.dll.libs += $(CONTRIB.build/)lib/libmfx.a
+endif
+
 ifeq (1,$(FEATURE.mp4v2))
 LIBHB.dll.libs += $(CONTRIB.build/)lib/libmp4v2.a
 endif
index 767e8d314d3b401a108feace118ba786912845e8..ff53ebbe9333224f8dc93804284d56421ad03b41 100644 (file)
@@ -207,6 +207,7 @@ static int avformatInit( hb_mux_object_t * m )
     switch (job->vcodec)
     {
         case HB_VCODEC_X264:
+        case HB_VCODEC_QSV_H264:
             track->st->codec->codec_id = AV_CODEC_ID_H264;
 
             /* Taken from x264 muxers.c */
@@ -1015,8 +1016,8 @@ static int avformatMux(hb_mux_object_t *m, hb_mux_data_t *track, hb_buffer_t *bu
     pkt.pts = pts;
     pkt.duration = duration;
 
-    if (track->type == MUX_TYPE_VIDEO &&
-        (job->vcodec == HB_VCODEC_X264 || job->vcodec & HB_VCODEC_FFMPEG_MASK))
+    if (track->type == MUX_TYPE_VIDEO && ((job->vcodec & HB_VCODEC_H264_MASK) ||
+                                          (job->vcodec & HB_VCODEC_FFMPEG_MASK)))
     {
         if (buf->s.frametype == HB_FRAME_IDR)
             pkt.flags |= AV_PKT_FLAG_KEY;
index ca72a7be8ec04c89161810cae52bdeaeefe3e6cb..f96a60e76d9c9161e85224fdd822321c17dd8e54 100644 (file)
@@ -55,6 +55,49 @@ static uint8_t * create_flac_header( uint8_t *data, int size )
     return out;
 }
 
+static uint8_t* create_h264_header(hb_job_t *job, int *size)
+{
+    /* Taken from x264's muxers.c */
+    int avcC_len  = (5 +
+                     1 + 2 + job->config.h264.sps_length +
+                     1 + 2 + job->config.h264.pps_length);
+#define MAX_AVCC_LEN 5 + 1 + 2 + 1024 + 1 + 2 + 1024 // FIXME
+    if (avcC_len > MAX_AVCC_LEN)
+    {
+        hb_log("create_h264_header: H.264 header too long (%d, max: %d)",
+               avcC_len, MAX_AVCC_LEN);
+        return NULL;
+    }
+    uint8_t *avcC = malloc(avcC_len);
+    if (avcC == NULL)
+    {
+        return NULL;
+    }
+
+    avcC[0] = 1;
+    avcC[1] = job->config.h264.sps[1]; /* AVCProfileIndication */
+    avcC[2] = job->config.h264.sps[2]; /* profile_compat */
+    avcC[3] = job->config.h264.sps[3]; /* AVCLevelIndication */
+    avcC[4] = 0xff; // nalu size length is four bytes
+    avcC[5] = 0xe1; // one sps
+
+    avcC[6] = job->config.h264.sps_length >> 8;
+    avcC[7] = job->config.h264.sps_length;
+    memcpy(avcC + 8, job->config.h264.sps, job->config.h264.sps_length);
+
+    avcC[8  + job->config.h264.sps_length] = 1; // one pps
+    avcC[9  + job->config.h264.sps_length] = job->config.h264.pps_length >> 8;
+    avcC[10 + job->config.h264.sps_length] = job->config.h264.pps_length;
+    memcpy(avcC + 11 + job->config.h264.sps_length,
+           job->config.h264.pps, job->config.h264.pps_length);
+
+    if (size != NULL)
+    {
+        *size = avcC_len;
+    }
+    return avcC;
+}
+
 /**********************************************************************
  * MKVInit
  **********************************************************************
@@ -97,33 +140,15 @@ static int MKVInit( hb_mux_object_t * m )
     switch (job->vcodec)
     {
         case HB_VCODEC_X264:
-            track->codecID = MK_VCODEC_MP4AVC;
-            /* Taken from x264 muxers.c */
-            avcC_len = 5 + 1 + 2 + job->config.h264.sps_length + 1 + 2 + job->config.h264.pps_length;
-            avcC = malloc(avcC_len);
-            if (avcC == NULL) {
+        case HB_VCODEC_QSV_H264:
+            avcC = create_h264_header(job, &avcC_len);
+            if (avcC == NULL)
+            {
                 free(track);
                 return -1;
             }
-
-            avcC[0] = 1;
-            avcC[1] = job->config.h264.sps[1];      /* AVCProfileIndication */
-            avcC[2] = job->config.h264.sps[2];      /* profile_compat */
-            avcC[3] = job->config.h264.sps[3];      /* AVCLevelIndication */
-            avcC[4] = 0xff; // nalu size length is four bytes
-            avcC[5] = 0xe1; // one sps
-
-            avcC[6] = job->config.h264.sps_length >> 8;
-            avcC[7] = job->config.h264.sps_length;
-
-            memcpy(avcC+8, job->config.h264.sps, job->config.h264.sps_length);
-
-            avcC[8+job->config.h264.sps_length] = 1; // one pps
-            avcC[9+job->config.h264.sps_length] = job->config.h264.pps_length >> 8;
-            avcC[10+job->config.h264.sps_length] = job->config.h264.pps_length;
-
-            memcpy( avcC+11+job->config.h264.sps_length, job->config.h264.pps, job->config.h264.pps_length );
-            track->codecPrivate = avcC;
+            track->codecID          = MK_VCODEC_MP4AVC;
+            track->codecPrivate     = avcC;
             track->codecPrivateSize = avcC_len;
             if (job->areBframes)
                 track->minCache = 1;
@@ -516,12 +541,12 @@ static int MKVMux(hb_mux_object_t *m, hb_mux_data_t *mux_data, hb_buffer_t *buf)
     }
     mk_addFrameData(m->file, mux_data->track, buf->data, buf->size);
     mk_setFrameFlags(m->file, mux_data->track, timecode,
-                     (((job->vcodec == HB_VCODEC_X264 || 
-                        (job->vcodec & HB_VCODEC_FFMPEG_MASK)) && 
-                       mux_data == job->mux_data) ? 
-                            (buf->s.frametype == HB_FRAME_IDR) : 
-                            ((buf->s.frametype & HB_FRAME_KEY) != 0)), 0 );
-    hb_buffer_close( &buf );
+                     ((mux_data == job->mux_data &&
+                       ((job->vcodec & HB_VCODEC_H264_MASK) ||
+                        (job->vcodec & HB_VCODEC_FFMPEG_MASK))) ?
+                      (buf->s.frametype == HB_FRAME_IDR)        :
+                      (buf->s.frametype  & HB_FRAME_KEY) != 0), 0);
+    hb_buffer_close(&buf);
     return 0;
 }
 
index 6f7ecab5407e56e8853c48edb8dcb9b867e95d8a..bd706d29c85227359da4d6b4c3ca576a81c3b348 100644 (file)
@@ -136,7 +136,7 @@ static int MP4Init( hb_mux_object_t * m )
         return 0;
     }
 
-    if( job->vcodec == HB_VCODEC_X264 )
+    if (job->vcodec & HB_VCODEC_H264_MASK)
     {
         /* Stolen from mp4creator */
         MP4SetVideoProfileLevel( m->file, 0x7F );
@@ -691,8 +691,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
     if( mux_data == job->mux_data )
     {
         /* Video */
-        if( job->vcodec == HB_VCODEC_X264 ||
-            ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
+        if ((job->vcodec & HB_VCODEC_H264_MASK) ||
+            (job->vcodec & HB_VCODEC_FFMPEG_MASK))
         {
             if ( buf && buf->s.start < buf->s.renderOffset )
             {
@@ -713,8 +713,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
 
         stop = buf->s.start + buf->s.duration;
 
-        if( job->vcodec == HB_VCODEC_X264 ||
-            ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
+        if ((job->vcodec & HB_VCODEC_H264_MASK) ||
+            (job->vcodec & HB_VCODEC_FFMPEG_MASK))
         {
             // x264 supplies us with DTS, so offset is PTS - DTS
             offset = buf->s.start - buf->s.renderOffset;
@@ -751,8 +751,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
             }
         }
 
-        if( job->vcodec == HB_VCODEC_X264 ||
-            ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
+        if ((job->vcodec & HB_VCODEC_H264_MASK) ||
+            (job->vcodec & HB_VCODEC_FFMPEG_MASK))
         {
             // x264 supplies us with DTS
             if ( m->delay_buf )
@@ -829,9 +829,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
     }
 
     /* Here's where the sample actually gets muxed. */
-    if( ( job->vcodec == HB_VCODEC_X264 ||
-        ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
-        && mux_data == job->mux_data )
+    if (mux_data == job->mux_data && ((job->vcodec & HB_VCODEC_H264_MASK) ||
+                                      (job->vcodec & HB_VCODEC_FFMPEG_MASK)))
     {
         /* Compute dependency flags.
          *
index 9b9ab020051ee004da914fbbe54dafe39febe6ee..94bb952277d956c3c0897bf9e2bef120f8f9494a 100644 (file)
@@ -141,6 +141,27 @@ uint64_t hb_get_date()
     return( (uint64_t) tv.tv_sec * 1000 + (uint64_t) tv.tv_usec / 1000 );
 }
 
+uint64_t hb_get_time_us()
+{
+#ifdef SYS_MINGW
+    static LARGE_INTEGER frequency;
+    LARGE_INTEGER cur_time;
+
+    if (frequency.QuadPart == 0)
+    {
+          QueryPerformanceFrequency(&frequency);
+    }
+
+    QueryPerformanceCounter(&cur_time);
+
+    return (uint64_t)(1000000 * cur_time.QuadPart / frequency.QuadPart);
+#else
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return ((uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec);
+#endif
+}
+
 /************************************************************************
  * hb_snooze()
  ************************************************************************
index 38921300de8bafbd660f7b27e7009cee1c7758ce..a87b7ebd65eb80c697651226797da27113fdb595 100644 (file)
@@ -36,7 +36,11 @@ extern void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx);
 /************************************************************************
  * Utils
  ***********************************************************************/
+// provide time in ms
 uint64_t hb_get_date();
+// provide time in us
+uint64_t hb_get_time_us();
+
 void     hb_snooze( int delay );
 int      hb_platform_init();
 #ifdef SYS_MINGW
index 0d7dde7ffaad8bb85a5168ac327ba04c5188a2fa..507662f36ae6bf437f344e5375b7fbd77423a81a 100644 (file)
@@ -865,6 +865,10 @@ skip_preview:
         title->color_transfer = vid_info.color_transfer;
         title->color_matrix = vid_info.color_matrix;
 
+#ifdef USE_QSV
+        title->qsv_decode_support = vid_info.qsv_decode_support;
+#endif
+
         // compute the aspect ratio based on the storage dimensions and the
         // pixel aspect ratio (if supplied) or just storage dimensions if no PAR.
         title->aspect = (double)title->width / (double)title->height;
index c04e517d44ff6408931c42b22c1994081d8ef3ed..8134688b328fd2117dfa1ffbce6dde0aea236ab4 100644 (file)
@@ -527,6 +527,27 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
             hb_unlock( pv->common->mutex );
 
             UpdateSearchState( w, next_start );
+#ifdef USE_QSV
+            // reclaim QSV resources before dropping the buffer
+            // when decoding without QSV, the QSV atom will be NULL
+            if (job != NULL && job->qsv != NULL && next->qsv_details.qsv_atom != NULL)
+            {
+                av_qsv_stage *stage = av_qsv_get_last_stage(next->qsv_details.qsv_atom);
+                if (stage != NULL)
+                {
+                    av_qsv_wait_on_sync(job->qsv, stage);
+                    if (stage->out.sync->in_use > 0)
+                    {
+                        ff_qsv_atomic_dec(&stage->out.sync->in_use);
+                    }
+                    if (stage->out.p_surface->Data.Locked > 0)
+                    {
+                        ff_qsv_atomic_dec(&stage->out.p_surface->Data.Locked);
+                    }
+                }
+                av_qsv_flush_stages(job->qsv->pipes, &next->qsv_details.qsv_atom);
+            }
+#endif
             hb_buffer_close( &next );
 
             return HB_WORK_OK;
@@ -720,6 +741,29 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
             // don't drop a chapter mark when we drop the buffer
             sync->chap_mark = next->s.new_chap;
         }
+
+#ifdef USE_QSV
+        // reclaim QSV resources before dropping the buffer
+        // when decoding without QSV, the QSV atom will be NULL
+        if (job != NULL && job->qsv != NULL && next->qsv_details.qsv_atom != NULL)
+        {
+            av_qsv_stage *stage = av_qsv_get_last_stage(next->qsv_details.qsv_atom);
+            if (stage != NULL)
+            {
+                av_qsv_wait_on_sync(job->qsv, stage);
+                if (stage->out.sync->in_use > 0)
+                {
+                    ff_qsv_atomic_dec(&stage->out.sync->in_use);
+                }
+                if (stage->out.p_surface->Data.Locked > 0)
+                {
+                    ff_qsv_atomic_dec(&stage->out.p_surface->Data.Locked);
+                }
+            }
+            av_qsv_flush_stages(job->qsv->pipes, &next->qsv_details.qsv_atom);
+        }
+#endif
+
         hb_buffer_close( &next );
         return HB_WORK_OK;
     }
index b23a3619a23b5b212fd61381eb4e9ed2e641d1c4..7f00ddab39f8b437a9e61fe6730885c3d6733251 100644 (file)
 #include "a52dec/a52.h"
 #include "libavformat/avformat.h"
 
+#ifdef USE_QSV
+#include "qsv_common.h"
+#include "qsv_filter_pp.h"
+#endif
+
 typedef struct
 {
     hb_list_t * jobs;
@@ -231,8 +236,18 @@ void hb_display_job_info(hb_job_t *job)
     
     hb_log(" * video track");
     
-    hb_log("   + decoder: %s", title->video_codec_name );
-    
+#ifdef USE_QSV
+    if (hb_qsv_decode_is_enabled(job))
+    {
+        hb_log("   + decoder: %s",
+               hb_qsv_decode_get_codec_name(title->video_codec_param));
+    }
+    else
+#endif
+    {
+        hb_log("   + decoder: %s", title->video_codec_name);
+    }
+
     if( title->video_bitrate )
     {
         hb_log( "     + bitrate %d kbps", title->video_bitrate / 1000 );
@@ -307,15 +322,15 @@ void hb_display_job_info(hb_job_t *job)
         {
             hb_log("     + options: %s", job->advanced_opts);
         }
-        if( job->h264_profile && *job->h264_profile &&
-            job->vcodec == HB_VCODEC_X264 )
+        if (job->h264_profile != NULL && *job->h264_profile &&
+            (job->vcodec & HB_VCODEC_H264_MASK))
         {
-            hb_log( "     + h264 profile: %s", job->h264_profile );
+            hb_log("     + h264 profile: %s", job->h264_profile);
         }
-        if( job->h264_level && *job->h264_level &&
-            job->vcodec == HB_VCODEC_X264 )
+        if (job->h264_level != NULL && *job->h264_level &&
+            (job->vcodec & HB_VCODEC_H264_MASK))
         {
-            hb_log( "     + h264 level: %s", job->h264_level );
+            hb_log("     + h264 level: %s", job->h264_level);
         }
 
         if (job->vquality >= 0)
@@ -659,6 +674,114 @@ static void do_job(hb_job_t *job)
         }
     }
 
+#ifdef USE_QSV
+    /*
+     * When QSV is used for decoding, not all CPU-based filters are supported,
+     * so we need to do a little extra setup here.
+     */
+    if (hb_qsv_decode_is_enabled(job))
+    {
+        int vpp_settings[7];
+        int num_cpu_filters = 0;
+        hb_filter_object_t *filter;
+        // default values for VPP filter
+        vpp_settings[0] = job->title->width;
+        vpp_settings[1] = job->title->height;
+        vpp_settings[2] = job->title->crop[0];
+        vpp_settings[3] = job->title->crop[1];
+        vpp_settings[4] = job->title->crop[2];
+        vpp_settings[5] = job->title->crop[3];
+        vpp_settings[6] = 0; // deinterlace: off
+        if (job->list_filter != NULL && hb_list_count(job->list_filter) > 0)
+        {
+            while (hb_list_count(job->list_filter) > num_cpu_filters)
+            {
+                filter = hb_list_item(job->list_filter, num_cpu_filters);
+                switch (filter->id)
+                {
+                    // cropping and scaling always done via VPP filter
+                    case HB_FILTER_CROP_SCALE:
+                        if (filter->settings == NULL || *filter->settings == '\0')
+                        {
+                            // VPP defaults were set above, so not a problem
+                            // however, this should never happen, print an error
+                            hb_error("do_job: '%s': no settings!", filter->name);
+                        }
+                        else
+                        {
+                            sscanf(filter->settings, "%d:%d:%d:%d:%d:%d",
+                                   &vpp_settings[0], &vpp_settings[1],
+                                   &vpp_settings[2], &vpp_settings[3],
+                                   &vpp_settings[4], &vpp_settings[5]);
+                        }
+                        hb_list_rem(job->list_filter, filter);
+                        hb_filter_close(&filter);
+                        break;
+
+                    // pick VPP or CPU deinterlace depending on settings
+                    case HB_FILTER_DEINTERLACE:
+                        if (filter->settings == NULL || !strcmp(filter->settings, "qsv"))
+                        {
+                            // deinterlacing via VPP filter
+                            vpp_settings[6] = 1;
+                            hb_list_rem(job->list_filter, filter);
+                            hb_filter_close(&filter);
+                        }
+                        else
+                        {
+                            // validated
+                            num_cpu_filters++;
+                        }
+                        break;
+
+                    // then, validated filters
+                    case HB_FILTER_ROTATE: // TODO: use Media SDK for this
+                    case HB_FILTER_RENDER_SUB:
+                        num_cpu_filters++;
+                        break;
+
+                    // finally, drop all unsupported filters
+                    default:
+                        hb_log("do_job: full QSV path, removing unsupported filter '%s'",
+                               filter->name);
+                        hb_list_rem(job->list_filter, filter);
+                        hb_filter_close(&filter);
+                        break;
+                }
+            }
+            if (num_cpu_filters > 0)
+            {
+                // we need filters to copy to system memory and back
+                filter = hb_filter_init(HB_FILTER_QSV_PRE);
+                hb_add_filter(job, filter, NULL);
+                filter = hb_filter_init(HB_FILTER_QSV_POST);
+                hb_add_filter(job, filter, NULL);
+            }
+            if (vpp_settings[0] != job->title->width  ||
+                vpp_settings[1] != job->title->height ||
+                vpp_settings[2] >= 1 /* crop */       ||
+                vpp_settings[3] >= 1 /* crop */       ||
+                vpp_settings[4] >= 1 /* crop */       ||
+                vpp_settings[5] >= 1 /* crop */       ||
+                vpp_settings[6] >= 1 /* deinterlace */)
+            {
+                // we need the VPP filter
+                char *settings = hb_strdup_printf("%d:%d:%d:%d:%d:%d_dei:%d",
+                                                  vpp_settings[0],
+                                                  vpp_settings[1],
+                                                  vpp_settings[2],
+                                                  vpp_settings[3],
+                                                  vpp_settings[4],
+                                                  vpp_settings[5],
+                                                  vpp_settings[6]);
+                filter = hb_filter_init(HB_FILTER_QSV);
+                hb_add_filter(job, filter, settings);
+                free(settings);
+            }
+        }
+    }
+#endif
+
     // Filters have an effect on settings.
     // So initialize the filters and update the job.
     if( job->list_filter && hb_list_count( job->list_filter ) )
@@ -720,12 +843,25 @@ static void do_job(hb_job_t *job)
             }
         }
     }
-    
-    job->fifo_mpeg2  = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE );
-    job->fifo_raw    = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
-    job->fifo_sync   = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
-    job->fifo_mpeg4  = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE );
-    job->fifo_render = NULL; // Attached to filter chain
+
+#ifdef USE_QSV
+    if (hb_qsv_decode_is_enabled(job))
+    {
+        job->fifo_mpeg2  = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE );
+        job->fifo_raw    = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE );
+        job->fifo_sync   = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE );
+        job->fifo_render = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE );
+        job->fifo_mpeg4  = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE );
+    }
+    else
+#endif
+    {
+        job->fifo_mpeg2  = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE );
+        job->fifo_raw    = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
+        job->fifo_sync   = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE );
+        job->fifo_mpeg4  = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE );
+        job->fifo_render = NULL; // Attached to filter chain
+    }
 
     /* Audio fifos must be initialized before sync */
     if (!job->indepth_scan)
@@ -1028,6 +1164,9 @@ static void do_job(hb_job_t *job)
         case HB_VCODEC_X264:
             w = hb_get_work( WORK_ENCX264 );
             break;
+        case HB_VCODEC_QSV_H264:
+            w = hb_get_work( WORK_ENCQSV );
+            break;
         case HB_VCODEC_THEORA:
             w = hb_get_work( WORK_ENCTHEORA );
             break;
@@ -1524,8 +1663,27 @@ static void filter_loop( void * _f )
         }
 
         buf_out = NULL;
+
+#ifdef USE_QSV
+        hb_buffer_t *last_buf_in = buf_in;
+#endif
+
         f->status = f->work( f, &buf_in, &buf_out );
 
+#ifdef USE_QSV
+        if (f->status == HB_FILTER_DELAY &&
+            last_buf_in->qsv_details.filter_details != NULL && buf_out == NULL)
+        {
+            hb_filter_private_t_qsv *qsv_user = buf_in ? buf_in->qsv_details.filter_details : last_buf_in->qsv_details.filter_details ;
+            qsv_user->post.status = f->status;
+
+            hb_lock(qsv_user->post.frame_completed_lock);
+            qsv_user->post.frame_go = 1;
+            hb_cond_broadcast(qsv_user->post.frame_completed);
+            hb_unlock(qsv_user->post.frame_completed_lock);
+
+        }
+#endif
         if ( buf_out && f->chapter_val && f->chapter_time <= buf_out->s.start )
         {
             buf_out->s.new_chap = f->chapter_val;
index 9a98017ce7ba6480844985be8859b3efe98c06f8..d558372ab2f18fd052dab485b54eb109ed8cac9a 100644 (file)
@@ -1175,6 +1175,8 @@ def createCLI():
     grp.add_option( '--disable-gst', default=False, action='store_true', help=h )
     h = IfHost( 'enable use of ffmpeg mpeg2 decoding', '*-*-*', none=optparse.SUPPRESS_HELP ).value
     grp.add_option( '--enable-ff-mpeg2', default=False, action='store_true', help=h )
+    h = IfHost( 'enable use of Intel Quick Sync Video hardware acceleration', '*-*-*', none=optparse.SUPPRESS_HELP ).value
+    grp.add_option( '--enable-qsv', default=False, action='store_true', help=h )
 
     h = IfHost( 'enable use of fdk-aac encoder', '*-*-*', none=optparse.SUPPRESS_HELP ).value
     grp.add_option( '--enable-fdk-aac', dest="enable_fdk_aac", default=not host.match( '*-*-darwin*' ), action='store_true', help=h )
@@ -1645,6 +1647,7 @@ int main ()
     doc.add( 'FEATURE.mp4v2',      int( options.enable_mp4v2 ))
     doc.add( 'FEATURE.libmkv',     int( options.enable_libmkv ))
     doc.add( 'FEATURE.avformat',   int( options.enable_avformat ))
+    doc.add( 'FEATURE.qsv',        int( options.enable_qsv ))
     doc.add( 'FEATURE.xcode',      int( not (Tools.xcodebuild.fail or options.disable_xcode or options.cross) ))
 
     if not Tools.xcodebuild.fail and not options.disable_xcode:
index 2554c11e7ccd5a677b1533777aa7f9891f9b57a6..bf6c5f4ec772dc03874a2b1409a478ce8775a220 100644 (file)
@@ -68,6 +68,10 @@ ifneq ($(HAS.pthread),1)
 endif
 endif
 
+ifeq (1,$(FEATURE.qsv))
+    MODULES += contrib/libmfx
+endif
+
 MODULES += contrib/x264
 
 ifneq (,$(filter $(BUILD.system),cygwin mingw))
index 66e95f2ded71095948c1e4df60f749ef9f0a8662..85c59533c578060059a6b60952f848866408bf0d 100644 (file)
@@ -19,6 +19,11 @@ TEST.GCC.l = \
         samplerate swscale theoraenc theoradec vorbis vorbisenc x264 \
         bluray xml2 bz2 z
 
+ifeq (1,$(FEATURE.qsv))
+    TEST.GCC.l += mfx
+    TEST.GCC.D += USE_QSV HAVE_THREADS=1
+endif
+
 ifeq (1,$(FEATURE.fdk_aac))
 TEST.GCC.l += fdk-aac
 endif
index e76258977b2ccf5a15ae228fe614d4470e91cb01..1f7fd3acf339a94b1eef3a3535ae07f64737f6ee 100644 (file)
 #include "lang.h"
 #include "parsecsv.h"
 
+#ifdef USE_QSV
+#include "qsv_common.h"
+#endif
+
 #if defined( __APPLE_CC__ )
 #import <CoreServices/CoreServices.h>
 #include <IOKit/IOKitLib.h>
@@ -132,6 +136,10 @@ static int    start_at_frame = 0;
 static int64_t stop_at_pts    = 0;
 static int    stop_at_frame = 0;
 static uint64_t min_title_duration = 10;
+#ifdef USE_QSV
+static int qsv_decode      =  1;
+static int qsv_async_depth = -1;
+#endif
 
 /* Exit cleanly on Ctrl-C */
 static volatile int die = 0;
@@ -1869,6 +1877,14 @@ static int HandleEvents( hb_handle_t * h )
                 job->vcodec = vcodec;
             }
 
+#ifdef USE_QSV
+            if (qsv_async_depth >= 0)
+            {
+                job->qsv_async_depth = qsv_async_depth;
+            }
+            job->qsv_decode = qsv_decode;
+#endif
+
             /* Grab audio tracks */
             if( atracks )
             {
@@ -3073,9 +3089,22 @@ static void ShowHelp()
     }
     if( len )
         fprintf( out, "%s\n", tmp );
-    fprintf( out,
-    "    -x, --encopts <string>  Specify advanced encoder options in the\n"
-    "                            same style as mencoder (x264 and ffmpeg only):\n"
+    fprintf(out,
+    "    -x, --encopts <string>  Specify advanced encoder options in the\n");
+#ifdef USE_QSV
+if (hb_qsv_available())
+{
+    fprintf(out,
+    "                            same style as mencoder (x264/qsv/ffmpeg only):\n");
+}
+else
+#endif
+{
+    fprintf(out,
+    "                            same style as mencoder (x264 and ffmpeg only):\n");
+}
+    
+    fprintf(out,
     "                            option1=value1:option2=value2\n"
     "        --h264-profile      When using x264, ensures compliance with the\n"
     "          <string>          specified H.264 profile:\n"
@@ -3332,7 +3361,14 @@ static void ShowHelp()
     "### Filters---------------------------------------------------------\n\n"
 
      "    -d, --deinterlace       Deinterlace video with Libav, yadif or mcdeint\n"
-     "          <fast/slow/slower/bob> or omitted (default settings)\n"
+     "          <fast/slow/slower/bob");
+#ifdef USE_QSV
+if (hb_qsv_available())
+{
+    fprintf(out, "/qsv");
+}
+#endif
+     fprintf( out, "> or omitted (default settings)\n"
      "           or\n"
      "          <YM:FD:MM:QP>     (default 0:-1:-1:1)\n"
      "    -5, --decomb            Selectively deinterlaces when it detects combing\n"
@@ -3415,10 +3451,22 @@ static void ShowHelp()
     "                            If \"number\" is omitted, the first srt is default.\n"
     "                            \"number\" is an 1 based index into the srt-file list\n"
     "\n"
+    );
 
-
+#ifdef USE_QSV
+if (hb_qsv_available())
+{
+    fprintf( out,
+    "### Intel Quick Sync Video------------------------------------------------------\n\n"
+    "    --disable-qsv-decoding  Force software decoding of the video track.\n"
+    "    --qsv-async-depth       Specifies how many asynchronous operations should be\n"
+    "                            performed before the result is explicitly synchronized.\n"
+    "                            Default: 4. If zero, the value is not specified.\n"
+    "\n"
     );
 }
+#endif
+}
 
 /****************************************************************************
  * ShowPresets:
@@ -3560,7 +3608,9 @@ static int ParseOptions( int argc, char ** argv )
     #define H264_LEVEL          286
     #define NORMALIZE_MIX       287
     #define AUDIO_DITHER        288
-    
+    #define QSV_BASELINE        289
+    #define QSV_ASYNC_DEPTH     290
+
     for( ;; )
     {
         static struct option long_options[] =
@@ -3568,7 +3618,12 @@ static int ParseOptions( int argc, char ** argv )
             { "help",        no_argument,       NULL,    'h' },
             { "update",      no_argument,       NULL,    'u' },
             { "verbose",     optional_argument, NULL,    'v' },
-            { "no-dvdnav",      no_argument,       NULL,    DVDNAV },
+            { "no-dvdnav",   no_argument,       NULL,    DVDNAV },
+#ifdef USE_QSV
+            { "qsv-baseline", no_argument,      NULL,    QSV_BASELINE },
+            { "qsv-async-depth", required_argument, NULL, QSV_ASYNC_DEPTH },
+            { "disable-qsv-decoding", no_argument, &qsv_decode, 0 },
+#endif
 
             { "format",      required_argument, NULL,    'f' },
             { "input",       required_argument, NULL,    'i' },
@@ -4185,6 +4240,21 @@ static int ParseOptions( int argc, char ** argv )
             case MIN_DURATION:
                 min_title_duration = strtol( optarg, NULL, 0 );
                 break;
+#ifdef USE_QSV
+            case QSV_BASELINE:
+                if (hb_qsv_available())
+                {
+                    /* XXX: for testing workarounds */
+                    hb_qsv_info->capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+                    hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_BRC;
+                    hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_TRELLIS;
+                    hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_LOOKAHEAD;
+                }
+                break;
+            case QSV_ASYNC_DEPTH:
+                qsv_async_depth = atoi(optarg);
+                break;
+#endif
             default:
                 fprintf( stderr, "unknown option (%s)\n", argv[cur_optind] );
                 return -1;