static int ffmpeg_va_GetFrameBuf( struct AVCodecContext *p_context, AVFrame *p_ff_pic ) { decoder_t *p_dec = (decoder_t *)p_context->opaque; decoder_sys_t *p_sys = p_dec->p_sys; vlc_va_t *p_va = p_sys->p_va; /* hwaccel_context is not present in old ffmpeg version */ if( vlc_va_Setup( p_va, &p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma, p_context->coded_width, p_context->coded_height ) ) { msg_Err( p_dec, "vlc_va_Setup failed" ); return -1; } if( vlc_va_Get( p_va, &p_ff_pic->opaque, &p_ff_pic->data[0] ) ) { msg_Err( p_dec, "vlc_va_Get failed" ); return -1; } p_ff_pic->data[3] = p_ff_pic->data[0]; p_ff_pic->type = FF_BUFFER_TYPE_USER; return 0; }
static int lavc_va_GetFrame(struct AVCodecContext *ctx, AVFrame *frame, int flags) { decoder_t *dec = ctx->opaque; decoder_sys_t *sys = dec->p_sys; vlc_va_t *va = sys->p_va; if (vlc_va_Setup(va, &ctx->hwaccel_context, &dec->fmt_out.video.i_chroma, ctx->coded_width, ctx->coded_height)) { msg_Err(dec, "hardware acceleration setup failed"); return -1; } if (vlc_va_Get(va, &frame->opaque, &frame->data[0])) { msg_Err(dec, "hardware acceleration picture allocation failed"); return -1; } /* data[0] must be non-NULL for libavcodec internal checks. * data[3] actually contains the format-specific surface handle. */ frame->data[3] = frame->data[0]; frame->buf[0] = av_buffer_create(frame->data[0], 0, va->release, frame->opaque, 0); if (unlikely(frame->buf[0] == NULL)) { vlc_va_Release(va, frame->opaque, frame->data[0]); return -1; } assert(frame->data[0] != NULL); (void) flags; return 0; }
/** * Callback used by libavcodec to get a frame buffer. * * It is used for direct rendering as well as to get the right PTS for each * decoded picture (even in indirect rendering mode). */ static int lavc_GetFrame(struct AVCodecContext *ctx, AVFrame *frame, int flags) { decoder_t *dec = ctx->opaque; decoder_sys_t *sys = dec->p_sys; picture_t *pic; for (unsigned i = 0; i < AV_NUM_DATA_POINTERS; i++) { frame->data[i] = NULL; frame->linesize[i] = 0; frame->buf[i] = NULL; } frame->opaque = NULL; wait_mt(sys); if (sys->p_va != NULL) { /* TODO: Move this to get_format(). We are screwed if it fails here. */ if (vlc_va_Setup(sys->p_va, ctx, &dec->fmt_out.video.i_chroma)) { post_mt(sys); msg_Err(dec, "hardware acceleration setup failed"); return -1; } } else if (!sys->b_direct_rendering) { post_mt(sys); return avcodec_default_get_buffer2(ctx, frame, flags); } /* The semaphore protects updates to fmt_out */ pic = ffmpeg_NewPictBuf(dec, ctx); post_mt(sys); if (pic == NULL) return -1; if (sys->p_va != NULL) return lavc_va_GetFrame(ctx, frame, pic); /* Some codecs set pix_fmt only after the 1st frame has been decoded, * so we need to check for direct rendering again. */ int ret = lavc_dr_GetFrame(ctx, frame, pic); if (ret) ret = avcodec_default_get_buffer2(ctx, frame, flags); return ret; }
static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context, const enum PixelFormat *pi_fmt ) { decoder_t *p_dec = p_context->opaque; decoder_sys_t *p_sys = p_dec->p_sys; vlc_va_t *p_va = p_sys->p_va; if( p_va != NULL ) vlc_va_Delete( p_va ); /* Enumerate available formats */ bool can_hwaccel = false; for( size_t i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ ) { const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(pi_fmt[i]); if (dsc == NULL) continue; bool hwaccel = (dsc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0; msg_Dbg( p_dec, "available %sware decoder output format %d (%s)", hwaccel ? "hard" : "soft", pi_fmt[i], dsc->name ); if (hwaccel) can_hwaccel = true; } if (!can_hwaccel) goto end; /* Profile and level information is needed now. * TODO: avoid code duplication with avcodec.c */ if( p_context->profile != FF_PROFILE_UNKNOWN) p_dec->fmt_in.i_profile = p_context->profile; if( p_context->level != FF_LEVEL_UNKNOWN) p_dec->fmt_in.i_level = p_context->level; p_va = vlc_va_New( VLC_OBJECT(p_dec), p_context, &p_dec->fmt_in ); if( p_va == NULL ) goto end; for( size_t i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ ) { if( p_va->pix_fmt != pi_fmt[i] ) continue; /* We try to call vlc_va_Setup when possible to detect errors when * possible (later is too late) */ if( p_context->width > 0 && p_context->height > 0 && vlc_va_Setup( p_va, &p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma, p_context->width, p_context->height ) ) { msg_Err( p_dec, "acceleration setup failure" ); break; } if( p_va->description ) msg_Info( p_dec, "Using %s for hardware decoding.", p_va->description ); /* FIXME this will disable direct rendering * even if a new pixel format is renegotiated */ p_sys->b_direct_rendering = false; p_sys->p_va = p_va; p_context->draw_horiz_band = NULL; return pi_fmt[i]; } vlc_va_Delete( p_va ); end: /* Fallback to default behaviour */ p_sys->p_va = NULL; return avcodec_default_get_format( p_context, pi_fmt ); }
static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_context, const enum PixelFormat *pi_fmt ) { decoder_t *p_dec = p_context->opaque; decoder_sys_t *p_sys = p_dec->p_sys; if (p_sys->p_va != NULL) { vlc_va_Delete(p_sys->p_va, p_context); p_sys->p_va = NULL; } /* Enumerate available formats */ enum PixelFormat swfmt = avcodec_default_get_format(p_context, pi_fmt); bool can_hwaccel = false; for( size_t i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ ) { const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(pi_fmt[i]); if (dsc == NULL) continue; bool hwaccel = (dsc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0; msg_Dbg( p_dec, "available %sware decoder output format %d (%s)", hwaccel ? "hard" : "soft", pi_fmt[i], dsc->name ); if (hwaccel) can_hwaccel = true; } if (!can_hwaccel) return swfmt; for( size_t i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ ) { enum PixelFormat hwfmt = pi_fmt[i]; p_dec->fmt_out.video.i_chroma = vlc_va_GetChroma(hwfmt, swfmt); if (p_dec->fmt_out.video.i_chroma == 0) continue; /* Unknown brand of hardware acceleration */ if (lavc_UpdateVideoFormat(p_dec, p_context, true)) continue; /* Unsupported brand of hardware acceleration */ vlc_va_t *va = vlc_va_New(VLC_OBJECT(p_dec), p_context, hwfmt, &p_dec->fmt_in); if (va == NULL) continue; /* Unsupported codec profile or such */ /* We try to call vlc_va_Setup when possible to detect errors when * possible (later is too late) */ if( p_context->width > 0 && p_context->height > 0 && vlc_va_Setup(va, p_context, &p_dec->fmt_out.video.i_chroma)) { msg_Err( p_dec, "acceleration setup failure" ); vlc_va_Delete(va, p_context); continue; } if (va->description != NULL) msg_Info(p_dec, "Using %s for hardware decoding", va->description); /* FIXME this will disable direct rendering * even if a new pixel format is renegotiated */ p_sys->b_direct_rendering = false; p_sys->p_va = va; p_context->draw_horiz_band = NULL; return pi_fmt[i]; } /* Fallback to default behaviour */ return swfmt; }
static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, AVFrame *p_ff_pic ) { decoder_t *p_dec = (decoder_t *)p_context->opaque; decoder_sys_t *p_sys = p_dec->p_sys; picture_t *p_pic; /* Set picture PTS */ ffmpeg_SetFrameBufferPts( p_dec, p_ff_pic ); /* */ p_ff_pic->opaque = NULL; if( p_sys->p_va ) { #ifdef HAVE_AVCODEC_VA /* hwaccel_context is not present in old fffmpeg version */ if( vlc_va_Setup( p_sys->p_va, &p_sys->p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma, p_sys->p_context->width, p_sys->p_context->height ) ) { msg_Err( p_dec, "vlc_va_Setup failed" ); return -1; } #else assert(0); #endif /* */ p_ff_pic->type = FF_BUFFER_TYPE_USER; /* FIXME what is that, should give good value */ p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg if( vlc_va_Get( p_sys->p_va, p_ff_pic ) ) { msg_Err( p_dec, "VaGrabSurface failed" ); return -1; } return 0; } else if( !p_sys->b_direct_rendering ) { /* Not much to do in indirect rendering mode. */ return avcodec_default_get_buffer( p_context, p_ff_pic ); } /* Some codecs set pix_fmt only after the 1st frame has been decoded, * so we need to check for direct rendering again. */ int i_width = p_sys->p_context->width; int i_height = p_sys->p_context->height; avcodec_align_dimensions( p_sys->p_context, &i_width, &i_height ); if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS || p_context->pix_fmt == PIX_FMT_PAL8 ) goto no_dr; p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma; /* Get a new picture */ p_pic = ffmpeg_NewPictBuf( p_dec, p_sys->p_context ); if( !p_pic ) goto no_dr; bool b_compatible = true; if( p_pic->p[0].i_pitch / p_pic->p[0].i_pixel_pitch < i_width || p_pic->p[0].i_lines < i_height ) b_compatible = false; for( int i = 0; i < p_pic->i_planes && b_compatible; i++ ) { unsigned i_align; switch( p_sys->i_codec_id ) { case CODEC_ID_SVQ1: case CODEC_ID_VP5: case CODEC_ID_VP6: case CODEC_ID_VP6F: case CODEC_ID_VP6A: i_align = 16; break; default: i_align = i == 0 ? 16 : 8; break; } if( p_pic->p[i].i_pitch % i_align ) b_compatible = false; if( (intptr_t)p_pic->p[i].p_pixels % i_align ) b_compatible = false; } if( p_context->pix_fmt == PIX_FMT_YUV422P && b_compatible ) { if( 2 * p_pic->p[1].i_pitch != p_pic->p[0].i_pitch || 2 * p_pic->p[2].i_pitch != p_pic->p[0].i_pitch ) b_compatible = false; } if( !b_compatible ) { decoder_DeletePicture( p_dec, p_pic ); goto no_dr; } if( p_sys->i_direct_rendering_used != 1 ) { msg_Dbg( p_dec, "using direct rendering" ); p_sys->i_direct_rendering_used = 1; } p_sys->p_context->draw_horiz_band = NULL; p_ff_pic->opaque = (void*)p_pic; p_ff_pic->type = FF_BUFFER_TYPE_USER; p_ff_pic->data[0] = p_pic->p[0].p_pixels; p_ff_pic->data[1] = p_pic->p[1].p_pixels; p_ff_pic->data[2] = p_pic->p[2].p_pixels; p_ff_pic->data[3] = NULL; /* alpha channel but I'm not sure */ p_ff_pic->linesize[0] = p_pic->p[0].i_pitch; p_ff_pic->linesize[1] = p_pic->p[1].i_pitch; p_ff_pic->linesize[2] = p_pic->p[2].i_pitch; p_ff_pic->linesize[3] = 0; decoder_LinkPicture( p_dec, p_pic ); /* FIXME what is that, should give good value */ p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg return 0; no_dr: if( p_sys->i_direct_rendering_used != 0 ) { msg_Warn( p_dec, "disabling direct rendering" ); p_sys->i_direct_rendering_used = 0; } return avcodec_default_get_buffer( p_context, p_ff_pic ); }
static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_codec, const enum PixelFormat *pi_fmt ) { decoder_t *p_dec = p_codec->opaque; decoder_sys_t *p_sys = p_dec->p_sys; if( p_sys->p_va ) { vlc_va_Delete( p_sys->p_va ); p_sys->p_va = NULL; } /* Try too look for a supported hw acceleration */ for( int i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ ) { static const char *ppsz_name[PIX_FMT_NB] = { [PIX_FMT_VDPAU_H264] = "PIX_FMT_VDPAU_H264", [PIX_FMT_VAAPI_IDCT] = "PIX_FMT_VAAPI_IDCT", [PIX_FMT_VAAPI_VLD] = "PIX_FMT_VAAPI_VLD", [PIX_FMT_VAAPI_MOCO] = "PIX_FMT_VAAPI_MOCO", #ifdef HAVE_AVCODEC_DXVA2 [PIX_FMT_DXVA2_VLD] = "PIX_FMT_DXVA2_VLD", #endif [PIX_FMT_YUYV422] = "PIX_FMT_YUYV422", [PIX_FMT_YUV420P] = "PIX_FMT_YUV420P", }; msg_Dbg( p_dec, "Available decoder output format %d (%s)", pi_fmt[i], ppsz_name[pi_fmt[i]] ?: "Unknown" ); /* Only VLD supported */ if( pi_fmt[i] == PIX_FMT_VAAPI_VLD ) { #ifdef HAVE_AVCODEC_VAAPI msg_Dbg( p_dec, "Trying VA API" ); p_sys->p_va = vlc_va_NewVaapi( p_sys->i_codec_id ); if( !p_sys->p_va ) msg_Warn( p_dec, "Failed to open VA API" ); #else continue; #endif } #ifdef HAVE_AVCODEC_DXVA2 if( pi_fmt[i] == PIX_FMT_DXVA2_VLD ) { msg_Dbg( p_dec, "Trying DXVA2" ); p_sys->p_va = vlc_va_NewDxva2( VLC_OBJECT(p_dec), p_sys->i_codec_id ); if( !p_sys->p_va ) msg_Warn( p_dec, "Failed to open DXVA2" ); } #endif if( p_sys->p_va && p_sys->p_context->width > 0 && p_sys->p_context->height > 0 ) { /* We try to call vlc_va_Setup when possible to detect errors when * possible (later is too late) */ if( vlc_va_Setup( p_sys->p_va, &p_sys->p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma, p_sys->p_context->width, p_sys->p_context->height ) ) { msg_Err( p_dec, "vlc_va_Setup failed" ); vlc_va_Delete( p_sys->p_va ); p_sys->p_va = NULL; } } if( p_sys->p_va ) { if( p_sys->p_va->description ) msg_Info( p_dec, "Using %s for hardware decoding.", p_sys->p_va->description ); /* FIXME this will disabled direct rendering * even if a new pixel format is renegociated */ p_sys->b_direct_rendering = false; p_sys->p_context->draw_horiz_band = NULL; return pi_fmt[i]; } } /* Fallback to default behaviour */ return avcodec_default_get_format( p_codec, pi_fmt ); }