You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user