1818 * See the License for the specific language governing permissions and
1919 * limitations under the License.
2020 */
21+ #ifdef HAVE_CONFIG_H
22+ #include "config.h"
23+ #endif
24+
2125#include <winpr/wlog.h>
2226#include <freerdp/log.h>
2327#include <freerdp/codec/h264.h>
2428#include <libavcodec/avcodec.h>
25- #include <libavutil/avutil.h>
2629#include <libavutil/opt.h>
27- #include <libavutil/mem.h>
30+
31+ #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT (55 , 9 , 0 )
32+ #include <libavutil/hwcontext.h>
33+ #else
34+ #pragma warning You have asked for VA-API decoding, but your version of libavutil is too old! Disabling.
35+ #undef WITH_VAAPI
36+ #endif
2837
2938#define TAG FREERDP_TAG("codec")
3039
@@ -56,6 +65,10 @@ static inline char* error_string(char* errbuf, size_t errbuf_size, int errnum)
5665 error_string((char[64]){0}, 64, errnum)
5766#endif
5867
68+ #ifdef WITH_VAAPI
69+ #define VAAPI_DEVICE "/dev/dri/renderD128"
70+ #endif
71+
5972struct _H264_CONTEXT_LIBAVCODEC
6073{
6174 AVCodec * codecDecoder ;
@@ -65,6 +78,11 @@ struct _H264_CONTEXT_LIBAVCODEC
6578 AVCodecParserContext * codecParser ;
6679 AVFrame * videoFrame ;
6780 AVPacket packet ;
81+ #ifdef WITH_VAAPI
82+ AVBufferRef * hwctx ;
83+ AVFrame * hwVideoFrame ;
84+ enum AVPixelFormat hw_pix_fmt ;
85+ #endif
6886};
6987typedef struct _H264_CONTEXT_LIBAVCODEC H264_CONTEXT_LIBAVCODEC ;
7088
@@ -197,20 +215,31 @@ static int libavcodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData,
197215
198216 if (status < 0 )
199217 {
200- WLog_ERR (TAG , "Failed to decode video frame (status=%d )" , status );
218+ WLog_ERR (TAG , "Failed to decode video frame (%s )" , av_err2str ( status ) );
201219 return -1 ;
202220 }
203221
222+ sys -> videoFrame -> format = AV_PIX_FMT_YUV420P ;
223+
204224 do
205225 {
226+ #ifdef WITH_VAAPI
227+ status = avcodec_receive_frame (sys -> codecDecoderContext , sys -> hwVideoFrame );
228+ #else
206229 status = avcodec_receive_frame (sys -> codecDecoderContext , sys -> videoFrame );
230+ #endif
207231 }
208232 while (status == AVERROR (EAGAIN ));
209233
210234 gotFrame = (status == 0 );
235+ #else
236+ #ifdef WITH_VAAPI
237+ status = avcodec_decode_video2 (sys -> codecDecoderContext , sys -> hwVideoFrame , & gotFrame ,
238+ & sys -> packet );
211239#else
212240 status = avcodec_decode_video2 (sys -> codecDecoderContext , sys -> videoFrame , & gotFrame ,
213241 & sys -> packet );
242+ #endif
214243#endif
215244
216245 if (status < 0 )
@@ -219,6 +248,28 @@ static int libavcodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData,
219248 return -1 ;
220249 }
221250
251+ #ifdef WITH_VAAPI
252+
253+ if (sys -> hwctx )
254+ {
255+ if (sys -> hwVideoFrame -> format == sys -> hw_pix_fmt )
256+ {
257+ sys -> videoFrame -> width = sys -> hwVideoFrame -> width ;
258+ sys -> videoFrame -> height = sys -> hwVideoFrame -> height ;
259+ status = av_hwframe_transfer_data (sys -> videoFrame , sys -> hwVideoFrame , 0 );
260+ }
261+ else
262+ {
263+ status = av_frame_copy (sys -> videoFrame , sys -> hwVideoFrame );
264+ }
265+ }
266+ else
267+ {
268+ status = av_frame_copy (sys -> videoFrame , sys -> hwVideoFrame );
269+ }
270+
271+ gotFrame = (status == 0 );
272+ #endif
222273#if 0
223274 WLog_INFO (TAG ,
224275 "libavcodec_decompress: frame decoded (status=%d, gotFrame=%d, width=%d, height=%d, Y=[%p,%d], U=[%p,%d], V=[%p,%d])" ,
@@ -361,6 +412,24 @@ static void libavcodec_uninit(H264_CONTEXT* h264)
361412#endif
362413 }
363414
415+ #ifdef WITH_VAAPI
416+
417+ if (sys -> hwVideoFrame )
418+ {
419+ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT (55 , 18 , 102 )
420+ av_frame_free (& sys -> hwVideoFrame );
421+ #else
422+ av_free (sys -> hwVideoFrame );
423+ #endif
424+ }
425+
426+ if (sys -> hwctx )
427+ {
428+ av_buffer_unref (& sys -> hwctx );
429+ }
430+
431+ #endif
432+
364433 if (sys -> codecParser )
365434 av_parser_close (sys -> codecParser );
366435
@@ -379,6 +448,25 @@ static void libavcodec_uninit(H264_CONTEXT* h264)
379448 h264 -> pSystemData = NULL ;
380449}
381450
451+ #ifdef WITH_VAAPI
452+ static enum AVPixelFormat libavcodec_get_format (struct AVCodecContext * ctx ,
453+ const enum AVPixelFormat * fmts )
454+ {
455+ H264_CONTEXT_LIBAVCODEC * sys = (H264_CONTEXT_LIBAVCODEC * ) ctx -> opaque ;
456+ const enum AVPixelFormat * p ;
457+
458+ for (p = fmts ; * p != AV_PIX_FMT_NONE ; p ++ )
459+ {
460+ if (* p == sys -> hw_pix_fmt )
461+ {
462+ return * p ;
463+ }
464+ }
465+
466+ return AV_PIX_FMT_NONE ;
467+ }
468+ #endif
469+
382470static BOOL libavcodec_init (H264_CONTEXT * h264 )
383471{
384472 H264_CONTEXT_LIBAVCODEC * sys ;
@@ -415,6 +503,25 @@ static BOOL libavcodec_init(H264_CONTEXT* h264)
415503 sys -> codecDecoderContext -> flags |= AV_CODEC_FLAG_TRUNCATED ;
416504 }
417505
506+ #ifdef WITH_VAAPI
507+
508+ if (!sys -> hwctx )
509+ {
510+ int ret = av_hwdevice_ctx_create (& sys -> hwctx , AV_HWDEVICE_TYPE_VAAPI , VAAPI_DEVICE , NULL , 0 );
511+
512+ if (ret < 0 )
513+ {
514+ WLog_ERR (TAG , "Could not initialize hw decoder: %s" , av_err2str (ret ));
515+ goto EXCEPTION ;
516+ }
517+ }
518+
519+ sys -> codecDecoderContext -> get_format = libavcodec_get_format ;
520+ sys -> hw_pix_fmt = AV_PIX_FMT_VAAPI ;
521+ sys -> codecDecoderContext -> hw_device_ctx = av_buffer_ref (sys -> hwctx );
522+ sys -> codecDecoderContext -> opaque = (void * ) sys ;
523+ #endif
524+
418525 if (avcodec_open2 (sys -> codecDecoderContext , sys -> codecDecoder , NULL ) < 0 )
419526 {
420527 WLog_ERR (TAG , "Failed to open libav codec" );
@@ -432,6 +539,9 @@ static BOOL libavcodec_init(H264_CONTEXT* h264)
432539
433540#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT (55 , 18 , 102 )
434541 sys -> videoFrame = av_frame_alloc ();
542+ #ifdef WITH_VAAPI
543+ sys -> hwVideoFrame = av_frame_alloc ();
544+ #endif
435545#else
436546 sys -> videoFrame = avcodec_alloc_frame ();
437547#endif
@@ -442,6 +552,15 @@ static BOOL libavcodec_init(H264_CONTEXT* h264)
442552 goto EXCEPTION ;
443553 }
444554
555+ #ifdef WITH_VAAPI
556+
557+ if (!sys -> hwVideoFrame )
558+ {
559+ WLog_ERR (TAG , "Failed to allocate libav hw frame" );
560+ goto EXCEPTION ;
561+ }
562+
563+ #endif
445564 sys -> videoFrame -> pts = 0 ;
446565 return TRUE;
447566EXCEPTION :
0 commit comments