Cleanup import video hardware accelerated and first attempt with

nvidia cards.
Still no error handling when the dimensions of the video are too
large
This commit is contained in:
eisneinechse
2018-09-08 21:17:24 -07:00
parent 16c8302f48
commit e7c1ced0da

View File

@@ -34,6 +34,8 @@ using namespace openshot;
int hw_de_on = 1; // Is set in UI
int hw_de_supported = 0; // Is set by FFmpegReader
AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE;
AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI;
FFmpegReader::FFmpegReader(string path)
: last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0),
@@ -108,112 +110,60 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64
#if IS_FFMPEG_3_2
#pragma message "You are compiling with experimental hardware decode"
#if defined(__linux__)
static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts)
{
const enum AVPixelFormat *p;
for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
if (*p == AV_PIX_FMT_VAAPI)
return *p;
if (*p == AV_PIX_FMT_VAAPI) {
hw_de_av_pix_fmt = AV_PIX_FMT_VAAPI;
hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI;
return *p;
}
if (*p == AV_PIX_FMT_CUDA) {
hw_de_av_pix_fmt = AV_PIX_FMT_CUDA;
hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA;
return *p;
}
}
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using VA-API.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1);
hw_de_supported = 0;
return AV_PIX_FMT_NONE;
}
int is_hardware_decode_supported(int codecid)
{
int ret;
switch (codecid) {
case AV_CODEC_ID_H264:
case AV_CODEC_ID_MPEG2VIDEO:
case AV_CODEC_ID_VC1:
case AV_CODEC_ID_WMV1:
case AV_CODEC_ID_WMV2:
case AV_CODEC_ID_WMV3:
ret = 1;
break;
default :
ret = 0;
break;
}
return ret;
}
#endif
#if defined(_WIN32)
// Works for Windows 64 and Windows 32
// FIXME Here goes the detection for Windows
// AV_HWDEVICE_TYPE_DXVA2 AV_PIX_FMT_DXVA2_VLD AV_HWDEVICE_TYPE_D3D11VA AV_PIX_FMT_D3D11
static enum AVPixelFormat get_dxva2_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts)
static enum AVPixelFormat get_dx_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts)
{
const enum AVPixelFormat *p;
for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
if (*p == AV_PIX_FMT_DXVA2_VLD)
return *p;
if (*p == AV_PIX_FMT_DXVA2_VLD) {
hw_de_av_pix_fmt = AV_PIX_FMT_DXVA2_VLD;
hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2;
return *p;
}
if (*p == AV_PIX_FMT_D3D11) {
hw_de_av_pix_fmt = AV_PIX_FMT_D3D11;
hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA;
return *p;
}
}
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using DXVA2.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1);
hw_de_supported = 0;
hw_de_av_pix_fmt = AV_PIX_FMT_NONE;
return AV_PIX_FMT_NONE;
}
int is_hardware_decode_supported(int codecid)
{
/* int ret;
switch (codecid) {
case AV_CODEC_ID_H264:
case AV_CODEC_ID_MPEG2VIDEO:
case AV_CODEC_ID_VC1:
case AV_CODEC_ID_WMV1:
case AV_CODEC_ID_WMV2:
case AV_CODEC_ID_WMV3:
ret = 1;
break;
default :
ret = 0;
break;
}
return ret;*/
return 0;
}
#endif
#if defined(__APPLE__)
// FIXME Here goes the detection for Mac
// Constants for MAC: AV_HWDEVICE_TYPE_QSV AV_PIX_FMT_QSV
int is_hardware_decode_supported(int codecid)
{
/* int ret;
switch (codecid) {
case AV_CODEC_ID_H264:
case AV_CODEC_ID_MPEG2VIDEO:
case AV_CODEC_ID_VC1:
case AV_CODEC_ID_WMV1:
case AV_CODEC_ID_WMV2:
case AV_CODEC_ID_WMV3:
ret = 1;
break;
default :
ret = 0;
break;
}
return ret;*/
return 0;
}
static int get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts)
{
while (*pix_fmts != AV_PIX_FMT_NONE) {
/* while (*pix_fmts != AV_PIX_FMT_NONE) {
if (*pix_fmts == AV_PIX_FMT_QSV) {
DecodeContext *decode = avctx->opaque;
AVHWFramesContext *frames_ctx;
AVQSVFramesContext *frames_hwctx;
int ret;
/* create a pool of surfaces to be used by the decoder */
// create a pool of surfaces to be used by the decoder
avctx->hw_frames_ctx = av_hwframe_ctx_alloc(decode->hw_device_ref);
if (!avctx->hw_frames_ctx)
return AV_PIX_FMT_NONE;
@@ -239,10 +189,40 @@ static int get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_f
}
fprintf(stderr, "The QSV pixel format not offered in get_format()\n");
*/
const enum AVPixelFormat *p;
for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
if (*p == AV_PIX_FMT_QSV) {
hw_de_av_pix_fmt = AV_PIX_FMT_QSV;
hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV;
return *p;
}
}
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using QSV.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1);
hw_de_supported = 0;
hw_de_av_pix_fmt = AV_PIX_FMT_NONE;
return AV_PIX_FMT_NONE;
}
#endif
int is_hardware_decode_supported(int codecid)
{
int ret;
switch (codecid) {
case AV_CODEC_ID_H264:
case AV_CODEC_ID_MPEG2VIDEO:
case AV_CODEC_ID_VC1:
case AV_CODEC_ID_WMV1:
case AV_CODEC_ID_WMV2:
case AV_CODEC_ID_WMV3:
ret = 1;
break;
default :
ret = 0;
break;
}
return ret;
}
#endif
@@ -303,9 +283,7 @@ void FFmpegReader::Open()
AVCodec *pCodec = avcodec_find_decoder(codecId);
pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec);
#if IS_FFMPEG_3_2
// #if defined(__linux__)
hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id);
// #endif
hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id);
#endif
// Set number of threads equal to number of processors (not to exceed 16)
pCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16);
@@ -319,42 +297,36 @@ void FFmpegReader::Open()
av_dict_set(&opts, "strict", "experimental", 0);
#if IS_FFMPEG_3_2
// #if defined(__linux__)
if (hw_de_on && hw_de_supported) {
// Open Hardware Acceleration
// Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set
char *dev_hw = getenv( "HW_DE_DEVICE_SET" );
// Check if it is there and writable
if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) {
dev_hw = NULL; // use default
}
hw_device_ctx = NULL;
// FIXME get_XXX_format
// FIXME AV_HWDEVICE_TYPE_....
// IMPORTANT: The get_format has different names because even for one plattform
// like Linux there are different modes of access like vaapi and vdpau and these
// should be chosen by the user in the future
#if defined(__linux__)
pCodecCtx->get_format = get_vaapi_format;
if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, dev_hw, NULL, 0) >= 0) {
#endif
#if defined(_WIN32)
pCodecCtx->get_format = get_dxva2_format;
if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, dev_hw, NULL, 0) >= 0) {
#endif
#if defined(__APPLE__)
pCodecCtx->get_format = get_qsv_format;
if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, dev_hw, NULL, 0) >= 0) {
#endif
if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) {
throw InvalidCodec("Hardware device reference create failed.", path);
}
}
else {
throw InvalidCodec("Hardware device create failed.", path);
if (hw_de_on && hw_de_supported) {
// Open Hardware Acceleration
// Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set
char *dev_hw = getenv( "HW_DE_DEVICE_SET" );
// Check if it is there and writable
if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) {
dev_hw = NULL; // use default
}
hw_device_ctx = NULL;
#if defined(__linux__)
pCodecCtx->get_format = get_vaapi_format;
//if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, dev_hw, NULL, 0) >= 0) {
#endif
#if defined(_WIN32)
pCodecCtx->get_format = get_dx_format;
//if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, dev_hw, NULL, 0) >= 0) {
#endif
#if defined(__APPLE__)
pCodecCtx->get_format = get_qsv_format;
//if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, dev_hw, NULL, 0) >= 0) {
#endif
if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, dev_hw, NULL, 0) >= 0) {
if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) {
throw InvalidCodec("Hardware device reference create failed.", path);
}
}
// #endif
else {
throw InvalidCodec("Hardware device create failed.", path);
}
}
#endif
// Open video codec
if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0)
@@ -446,14 +418,12 @@ void FFmpegReader::Close()
avcodec_flush_buffers(pCodecCtx);
AV_FREE_CONTEXT(pCodecCtx);
#if IS_FFMPEG_3_2
// #if defined(__linux__)
if (hw_de_on) {
if (hw_device_ctx) {
av_buffer_unref(&hw_device_ctx);
hw_device_ctx = NULL;
}
if (hw_de_on) {
if (hw_device_ctx) {
av_buffer_unref(&hw_device_ctx);
hw_device_ctx = NULL;
}
// #endif
}
#endif
}
if (info.has_audio)
@@ -949,37 +919,25 @@ bool FFmpegReader::GetAVFrame()
}
else {
AVFrame *next_frame2;
// #if defined(__linux__)
if (hw_de_on && hw_de_supported) {
next_frame2 = AV_ALLOCATE_FRAME();
}
else
// #endif
{
next_frame2 = next_frame;
}
pFrame = new AVFrame();
while (ret >= 0) {
ret = avcodec_receive_frame(pCodecCtx, next_frame2);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
if (ret != 0) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (invalid return frame received)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1);
}
// #if defined(__linux__)
if (hw_de_on && hw_de_supported) {
int err;
// FIXME AV_PIX_FMT_VAAPI
#if defined(__linux__)
if (next_frame2->format == AV_PIX_FMT_VAAPI) {
#endif
#if defined(__WIN32__)
if (next_frame2->format == AV_PIX_FMT_DXVA2_VLD) {
#endif
#if defined(__APPLE__)
if (next_frame2->format == AV_PIX_FMT_QSV) {
#endif
if (next_frame2->format == hw_de_av_pix_fmt) {
next_frame->format = AV_PIX_FMT_YUV420P;
if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to transfer data to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1);
@@ -990,11 +948,9 @@ bool FFmpegReader::GetAVFrame()
}
}
else
// #endif
{ // No hardware acceleration used -> no copy from GPU memory needed
next_frame = next_frame2;
}
//}
// TODO also handle possible further frames
// Use only the first frame like avcodec_decode_video2
if (frameFinished == 0 ) {
@@ -1009,11 +965,9 @@ bool FFmpegReader::GetAVFrame()
}
}
}
// #if defined(__linux__)
if (hw_de_on && hw_de_supported) {
AV_FREE_FRAME(&next_frame2);
}
// #endif
if (hw_de_on && hw_de_supported) {
AV_FREE_FRAME(&next_frame2);
}
}
#else
avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet);