#include "config.h"
+#if HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
#if CONFIG_VAAPI
#include "hwcontext_vaapi.h"
#endif
typedef struct QSVFramesContext {
mfxSession session_download;
+ int session_download_init;
mfxSession session_upload;
+ int session_upload_init;
+#if HAVE_PTHREADS
+ pthread_mutex_t session_lock;
+ pthread_cond_t session_cond;
+#endif
AVBufferRef *child_frames_ref;
mfxFrameSurface1 *surfaces_internal;
uint32_t fourcc;
} supported_pixel_formats[] = {
{ AV_PIX_FMT_NV12, MFX_FOURCC_NV12 },
+ { AV_PIX_FMT_BGRA, MFX_FOURCC_RGB4 },
{ AV_PIX_FMT_P010, MFX_FOURCC_P010 },
{ AV_PIX_FMT_PAL8, MFX_FOURCC_P8 },
};
MFXClose(s->session_download);
}
s->session_download = NULL;
+ s->session_download_init = 0;
if (s->session_upload) {
MFXVideoVPP_Close(s->session_upload);
MFXClose(s->session_upload);
}
s->session_upload = NULL;
+ s->session_upload_init = 0;
+
+#if HAVE_PTHREADS
+ pthread_mutex_destroy(&s->session_lock);
+ pthread_cond_destroy(&s->session_cond);
+#endif
av_freep(&s->mem_ids);
av_freep(&s->surface_ptrs);
!(req->Type & (MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT)) ||
!(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME))
return MFX_ERR_UNSUPPORTED;
- if (i->Width != i1->Width || i->Height != i1->Height ||
+ if (i->Width > i1->Width || i->Height > i1->Height ||
i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) {
av_log(ctx, AV_LOG_ERROR, "Mismatching surface properties in an "
"allocation request: %dx%d %d %d vs %dx%d %d %d\n",
s->mem_ids[i] = frames_hwctx->surfaces[i].Data.MemId;
}
- ret = qsv_init_internal_session(ctx, &s->session_download, 0);
- if (ret < 0)
- return ret;
+ s->session_download = NULL;
+ s->session_upload = NULL;
- ret = qsv_init_internal_session(ctx, &s->session_upload, 1);
- if (ret < 0)
- return ret;
+ s->session_download_init = 0;
+ s->session_upload_init = 0;
+
+#if HAVE_PTHREADS
+ pthread_mutex_init(&s->session_lock, NULL);
+ pthread_cond_init(&s->session_cond, NULL);
+#endif
return 0;
}
return ret;
}
+static int map_frame_to_surface(const AVFrame *frame, mfxFrameSurface1 *surface)
+{
+ switch (frame->format) {
+ case AV_PIX_FMT_NV12:
+ case AV_PIX_FMT_P010:
+ surface->Data.Y = frame->data[0];
+ surface->Data.UV = frame->data[1];
+ break;
+
+ case AV_PIX_FMT_YUV420P:
+ surface->Data.Y = frame->data[0];
+ surface->Data.U = frame->data[1];
+ surface->Data.V = frame->data[2];
+ break;
+
+ case AV_PIX_FMT_BGRA:
+ surface->Data.B = frame->data[0];
+ surface->Data.G = frame->data[0] + 1;
+ surface->Data.R = frame->data[0] + 2;
+ surface->Data.A = frame->data[0] + 3;
+ break;
+
+ default:
+ return MFX_ERR_UNSUPPORTED;
+ }
+ surface->Data.Pitch = frame->linesize[0];
+ surface->Data.TimeStamp = frame->pts;
+
+ return 0;
+}
+
static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
const AVFrame *src)
{
mfxSyncPoint sync = NULL;
mfxStatus err;
+ int ret = 0;
+
+ while (!s->session_download_init && !s->session_download && !ret) {
+#if HAVE_PTHREADS
+ if (pthread_mutex_trylock(&s->session_lock) == 0) {
+#endif
+ if (!s->session_download_init) {
+ ret = qsv_init_internal_session(ctx, &s->session_download, 0);
+ if (s->session_download)
+ s->session_download_init = 1;
+ }
+#if HAVE_PTHREADS
+ pthread_mutex_unlock(&s->session_lock);
+ pthread_cond_signal(&s->session_cond);
+ } else {
+ pthread_mutex_lock(&s->session_lock);
+ while (!s->session_download_init && !s->session_download) {
+ pthread_cond_wait(&s->session_cond, &s->session_lock);
+ }
+ pthread_mutex_unlock(&s->session_lock);
+ }
+#endif
+ }
+
+ if (ret < 0)
+ return ret;
if (!s->session_download) {
if (s->child_frames_ref)
}
out.Info = in->Info;
- out.Data.PitchLow = dst->linesize[0];
- out.Data.Y = dst->data[0];
- out.Data.U = dst->data[1];
- out.Data.V = dst->data[2];
- out.Data.A = dst->data[3];
+ map_frame_to_surface(dst, &out);
do {
err = MFXVideoVPP_RunFrameVPPAsync(s->session_download, in, &out, NULL, &sync);
mfxSyncPoint sync = NULL;
mfxStatus err;
+ int ret = 0;
+ /* make a copy if the input is not padded as libmfx requires */
+ AVFrame tmp_frame;
+ const AVFrame *src_frame;
+ int realigned = 0;
+
+
+ while (!s->session_upload_init && !s->session_upload && !ret) {
+#if HAVE_PTHREADS
+ if (pthread_mutex_trylock(&s->session_lock) == 0) {
+#endif
+ if (!s->session_upload_init) {
+ ret = qsv_init_internal_session(ctx, &s->session_upload, 1);
+ if (s->session_upload)
+ s->session_upload_init = 1;
+ }
+#if HAVE_PTHREADS
+ pthread_mutex_unlock(&s->session_lock);
+ pthread_cond_signal(&s->session_cond);
+ } else {
+ pthread_mutex_lock(&s->session_lock);
+ while (!s->session_upload_init && !s->session_upload) {
+ pthread_cond_wait(&s->session_cond, &s->session_lock);
+ }
+ pthread_mutex_unlock(&s->session_lock);
+ }
+#endif
+ }
+ if (ret < 0)
+ return ret;
+
+
+ if (src->height & 16 || src->linesize[0] & 16) {
+ realigned = 1;
+ memset(&tmp_frame, 0, sizeof(tmp_frame));
+ 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, 32);
+ if (ret < 0)
+ return ret;
+
+ ret = av_frame_copy(&tmp_frame, src);
+ if (ret < 0) {
+ av_frame_unref(&tmp_frame);
+ return ret;
+ }
+ }
+
+ src_frame = realigned ? &tmp_frame : src;
if (!s->session_upload) {
if (s->child_frames_ref)
- return qsv_transfer_data_child(ctx, dst, src);
+ return qsv_transfer_data_child(ctx, dst, src_frame);
av_log(ctx, AV_LOG_ERROR, "Surface upload not possible\n");
return AVERROR(ENOSYS);
}
in.Info = out->Info;
- in.Data.PitchLow = src->linesize[0];
- in.Data.Y = src->data[0];
- in.Data.U = src->data[1];
- in.Data.V = src->data[2];
- in.Data.A = src->data[3];
+ map_frame_to_surface(src_frame, &in);
do {
err = MFXVideoVPP_RunFrameVPPAsync(s->session_upload, &in, out, NULL, &sync);
return AVERROR_UNKNOWN;
}
+ if (realigned)
+ av_frame_unref(&tmp_frame);
+
return 0;
}