@ -47,6 +47,7 @@
# include "pixfmt.h"
# include "pixfmt.h"
# include "pixdesc.h"
# include "pixdesc.h"
# include "time.h"
# include "time.h"
# include "imgutils.h"
# define QSV_VERSION_ATLEAST(MAJOR, MINOR) \
# define QSV_VERSION_ATLEAST(MAJOR, MINOR) \
( MFX_VERSION_MAJOR > ( MAJOR ) | | \
( MFX_VERSION_MAJOR > ( MAJOR ) | | \
@ -90,6 +91,7 @@ typedef struct QSVFramesContext {
mfxExtOpaqueSurfaceAlloc opaque_alloc ;
mfxExtOpaqueSurfaceAlloc opaque_alloc ;
mfxExtBuffer * ext_buffers [ 1 ] ;
mfxExtBuffer * ext_buffers [ 1 ] ;
AVFrame realigned_tmp_frame ;
} QSVFramesContext ;
} QSVFramesContext ;
static const struct {
static const struct {
@ -137,6 +139,54 @@ static uint32_t qsv_get_d3d11va_bind_flags(int mem_type)
}
}
# endif
# endif
static int qsv_fill_border ( AVFrame * dst , const AVFrame * src )
{
const AVPixFmtDescriptor * desc ;
int i , planes_nb = 0 ;
if ( dst - > format ! = src - > format )
return AVERROR ( EINVAL ) ;
desc = av_pix_fmt_desc_get ( dst - > format ) ;
for ( i = 0 ; i < desc - > nb_components ; i + + )
planes_nb = FFMAX ( planes_nb , desc - > comp [ i ] . plane + 1 ) ;
for ( i = 0 ; i < planes_nb ; i + + ) {
int sheight , dheight , y ;
ptrdiff_t swidth = av_image_get_linesize ( src - > format ,
src - > width ,
i ) ;
ptrdiff_t dwidth = av_image_get_linesize ( dst - > format ,
dst - > width ,
i ) ;
const AVComponentDescriptor comp = desc - > comp [ i ] ;
if ( swidth < 0 | | dwidth < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " av_image_get_linesize failed \n " ) ;
return AVERROR ( EINVAL ) ;
}
sheight = src - > height ;
dheight = dst - > height ;
if ( i ) {
sheight = AV_CEIL_RSHIFT ( src - > height , desc - > log2_chroma_h ) ;
dheight = AV_CEIL_RSHIFT ( dst - > height , desc - > log2_chroma_h ) ;
}
//fill right padding
for ( y = 0 ; y < sheight ; y + + ) {
void * line_ptr = dst - > data [ i ] + y * dst - > linesize [ i ] + swidth ;
av_memcpy_backptr ( line_ptr ,
comp . depth > 8 ? 2 : 1 ,
dwidth - swidth ) ;
}
//fill bottom padding
for ( y = sheight ; y < dheight ; y + + ) {
memcpy ( dst - > data [ i ] + y * dst - > linesize [ i ] ,
dst - > data [ i ] + ( sheight - 1 ) * dst - > linesize [ i ] ,
dwidth ) ;
}
}
return 0 ;
}
static int qsv_device_init ( AVHWDeviceContext * ctx )
static int qsv_device_init ( AVHWDeviceContext * ctx )
{
{
AVQSVDeviceContext * hwctx = ctx - > hwctx ;
AVQSVDeviceContext * hwctx = ctx - > hwctx ;
@ -220,6 +270,7 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx)
av_freep ( & s - > surface_ptrs ) ;
av_freep ( & s - > surface_ptrs ) ;
av_freep ( & s - > surfaces_internal ) ;
av_freep ( & s - > surfaces_internal ) ;
av_freep ( & s - > handle_pairs_internal ) ;
av_freep ( & s - > handle_pairs_internal ) ;
av_frame_unref ( & s - > realigned_tmp_frame ) ;
av_buffer_unref ( & s - > child_frames_ref ) ;
av_buffer_unref ( & s - > child_frames_ref ) ;
}
}
@ -1014,12 +1065,13 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
QSVFramesContext * s = ctx - > internal - > priv ;
QSVFramesContext * s = ctx - > internal - > priv ;
mfxFrameSurface1 in = { { 0 } } ;
mfxFrameSurface1 in = { { 0 } } ;
mfxFrameSurface1 * out = ( mfxFrameSurface1 * ) dst - > data [ 3 ] ;
mfxFrameSurface1 * out = ( mfxFrameSurface1 * ) dst - > data [ 3 ] ;
mfxFrameInfo tmp_info ;
mfxSyncPoint sync = NULL ;
mfxSyncPoint sync = NULL ;
mfxStatus err ;
mfxStatus err ;
int ret = 0 ;
int ret = 0 ;
/* make a copy if the input is not padded as libmfx requires */
/* make a copy if the input is not padded as libmfx requires */
AVFrame tmp_frame ;
AVFrame * tmp_frame = & s - > realigned_ tmp_frame;
const AVFrame * src_frame ;
const AVFrame * src_frame ;
int realigned = 0 ;
int realigned = 0 ;
@ -1048,24 +1100,40 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
if ( ret < 0 )
if ( ret < 0 )
return ret ;
return ret ;
/* According to MSDK spec for mfxframeinfo, "Width must be a multiple of 16.
* Height must be a multiple of 16 for progressive frame sequence and a
* multiple of 32 otherwise . " , so allign all frames to 16 before uploading. */
if ( src - > height & 15 | | src - > linesize [ 0 ] & 15 ) {
if ( src - > height & 15 | | src - > linesize [ 0 ] & 15 ) {
realigned = 1 ;
realigned = 1 ;
memset ( & tmp_frame , 0 , sizeof ( tmp_frame ) ) ;
if ( tmp_frame - > format ! = src - > format | |
tmp_frame . format = src - > format ;
tmp_frame - > width ! = FFALIGN ( src - > width , 16 ) | |
tmp_frame . width = FFALIGN ( src - > width , 16 ) ;
tmp_frame - > height ! = FFALIGN ( src - > height , 16 ) ) {
tmp_frame . height = FFALIGN ( src - > height , 16 ) ;
av_frame_unref ( tmp_frame ) ;
ret = av_frame_get_buffer ( & tmp_frame , 0 ) ;
if ( ret < 0 )
tmp_frame - > format = src - > format ;
tmp_frame - > width = FFALIGN ( src - > width , 16 ) ;
tmp_frame - > height = FFALIGN ( src - > height , 16 ) ;
ret = av_frame_get_buffer ( tmp_frame , 0 ) ;
if ( ret < 0 )
return ret ;
}
ret = av_frame_copy ( tmp_frame , src ) ;
if ( ret < 0 ) {
av_frame_unref ( tmp_frame ) ;
return ret ;
return ret ;
}
ret = av_frame_copy ( & tmp_frame , src ) ;
ret = qsv_fill_border ( tmp_frame , src ) ;
if ( ret < 0 ) {
if ( ret < 0 ) {
av_frame_unref ( & tmp_frame ) ;
av_frame_unref ( tmp_frame ) ;
return ret ;
return ret ;
}
}
tmp_info = out - > Info ;
out - > Info . CropW = FFMIN ( out - > Info . Width , tmp_frame - > width ) ;
out - > Info . CropH = FFMIN ( out - > Info . Height , tmp_frame - > height ) ;
}
}
src_frame = realigned ? & tmp_frame : src ;
src_frame = realigned ? tmp_frame : src ;
if ( ! s - > session_upload ) {
if ( ! s - > session_upload ) {
if ( s - > child_frames_ref )
if ( s - > child_frames_ref )
@ -1097,8 +1165,10 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
return AVERROR_UNKNOWN ;
return AVERROR_UNKNOWN ;
}
}
if ( realigned )
if ( realigned ) {
av_frame_unref ( & tmp_frame ) ;
out - > Info . CropW = tmp_info . CropW ;
out - > Info . CropH = tmp_info . CropH ;
}
return 0 ;
return 0 ;
}
}