enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx , const PixelFormat * fmt ) { CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; if(!ctx->IsHardwareAllowed()) return ctx->m_dllAvCodec.avcodec_default_get_format(avctx, fmt); const PixelFormat * cur = fmt; while(*cur != PIX_FMT_NONE) { #ifdef HAVE_LIBVDPAU if(CVDPAU::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau")) { if(ctx->GetHardware()) return *cur; CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height); CVDPAU* vdp = new CVDPAU(); if(vdp->Open(avctx, *cur)) { ctx->SetHardware(vdp); return *cur; } else vdp->Release(); } #endif #ifdef HAS_DX if(DXVA::CDecoder::Supports(*cur) && g_guiSettings.GetBool("videoplayer.usedxva2")) { DXVA::CDecoder* dec = new DXVA::CDecoder(); if(dec->Open(avctx, *cur, ctx->m_uSurfacesCount)) { ctx->SetHardware(dec); return *cur; } else dec->Release(); } #endif #ifdef HAVE_LIBVA // mpeg4 vaapi decoding is disabled if(*cur == PIX_FMT_VAAPI_VLD && g_guiSettings.GetBool("videoplayer.usevaapi") && (avctx->codec_id != CODEC_ID_MPEG4 || g_advancedSettings.m_videoAllowMpeg4VAAPI)) { VAAPI::CDecoder* dec = new VAAPI::CDecoder(); if(dec->Open(avctx, *cur)) { ctx->SetHardware(dec); return *cur; } else dec->Release(); } #endif cur++; } return ctx->m_dllAvCodec.avcodec_default_get_format(avctx, fmt); }
void CVDPAU::FFReleaseBuffer(AVCodecContext *avctx, AVFrame *pic) { //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); vdpau_render_state * render; unsigned int i; CSharedLock lock(vdp->m_DecoderSection); render=(vdpau_render_state*)pic->data[0]; if(!render) { CLog::Log(LOGERROR, "CVDPAU::FFReleaseBuffer - invalid context handle provided"); return; } for(i=0; i<4; i++) pic->data[i]= NULL; // find render state in queue if (!vdp->IsSurfaceValid(render)) { CLog::Log(LOGDEBUG, "CVDPAU::FFReleaseBuffer - ignoring invalid buffer"); return; } render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; }
void CVDPAU::FFDrawSlice(struct AVCodecContext *s, const AVFrame *src, int offset[4], int y, int type, int height) { CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque; CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); // while we are waiting to recover we can't do anything CSharedLock lock(vdp->m_DecoderSection); { CSharedLock dLock(vdp->m_DisplaySection); if(vdp->m_DisplayState != VDPAU_OPEN) return; } if(src->linesize[0] || src->linesize[1] || src->linesize[2] || offset[0] || offset[1] || offset[2]) { CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided"); return; } VdpStatus vdp_st; vdpau_render_state * render; render = (vdpau_render_state*)src->data[0]; if(!render) { CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid context handle provided"); return; } // ffmpeg vc-1 decoder does not flush, make sure the data buffer is still valid if (!vdp->IsSurfaceValid(render)) { CLog::Log(LOGWARNING, "CVDPAU::FFDrawSlice - ignoring invalid buffer"); return; } uint32_t max_refs = 0; if(s->pix_fmt == PIX_FMT_VDPAU_H264) max_refs = render->info.h264.num_ref_frames; if(vdp->decoder == VDP_INVALID_HANDLE || vdp->vdpauConfigured == false || vdp->max_references < max_refs) { if(!vdp->ConfigVDPAU(s, max_refs)) return; } vdp_st = vdp->vdp_decoder_render(vdp->decoder, render->surface, (VdpPictureInfo const *)&(render->info), render->bitstream_buffers_used, render->bitstream_buffers); vdp->CheckStatus(vdp_st, __LINE__); }
enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx , const PixelFormat * fmt ) { CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; if(!ctx->IsHardwareAllowed()) return ctx->m_dllAvCodec.avcodec_default_get_format(avctx, fmt); const PixelFormat * cur = fmt; while(*cur != PIX_FMT_NONE) { #ifdef HAVE_LIBVDPAU if(CVDPAU::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.hwaccel")) { if(ctx->GetHardware()) return *cur; CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height); CVDPAU* vdp = new CVDPAU(); if(vdp->Open(avctx, *cur)) { ctx->SetHardware(vdp); return *cur; } else vdp->Release(); } #endif #ifdef HAS_DX if(DXVA::CDecoder::Supports(*cur) && g_guiSettings.GetBool("videoplayer.hwaccel")) { DXVA::CDecoder* dec = new DXVA::CDecoder(); if(dec->Open(avctx, *cur)) { ctx->SetHardware(dec); return *cur; } else dec->Release(); } #endif #ifdef HAVE_LIBVA if(*cur == PIX_FMT_VAAPI_VLD && g_guiSettings.GetBool("videoplayer.hwaccel")) { VAAPI::CDecoder* dec = new VAAPI::CDecoder(); if(dec->Open(avctx, *cur)) { ctx->SetHardware(dec); return *cur; } else dec->Release(); } #endif cur++; } return ctx->m_dllAvCodec.avcodec_default_get_format(avctx, fmt); }
void CVDPAU::FFDrawSlice(struct AVCodecContext *s, const AVFrame *src, int offset[4], int y, int type, int height) { CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)s->opaque; CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); /* while we are waiting to recover we can't do anything */ if(vdp->recover) return; if(src->linesize[0] || src->linesize[1] || src->linesize[2] || offset[0] || offset[1] || offset[2]) { CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid linesizes or offsets provided"); return; } VdpStatus vdp_st; vdpau_render_state * render; render = (vdpau_render_state*)src->data[0]; if(!render) { CLog::Log(LOGERROR, "CVDPAU::FFDrawSlice - invalid context handle provided"); return; } uint32_t max_refs = 0; if(s->pix_fmt == PIX_FMT_VDPAU_H264) max_refs = render->info.h264.num_ref_frames; if(vdp->decoder == VDP_INVALID_HANDLE || vdp->vdpauConfigured == false || vdp->max_references < max_refs) { if(!vdp->ConfigVDPAU(s, max_refs)) return; } vdp_st = vdp->vdp_decoder_render(vdp->decoder, render->surface, (VdpPictureInfo const *)&(render->info), render->bitstream_buffers_used, render->bitstream_buffers); vdp->CheckStatus(vdp_st, __LINE__); }
int CVDPAU::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic) { //CLog::Log(LOGNOTICE,"%s",__FUNCTION__); CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; CVDPAU* vdp = (CVDPAU*)ctx->GetHardware(); struct pictureAge* pA = &vdp->picAge; // while we are waiting to recover we can't do anything if(vdp->recover) { CLog::Log(LOGWARNING, "CVDPAU::FFGetBuffer - returning due to awaiting recovery"); return -1; } vdpau_render_state * render = NULL; // find unused surface for(unsigned int i = 0; i < vdp->m_videoSurfaces.size(); i++) { if(!(vdp->m_videoSurfaces[i]->state & (FF_VDPAU_STATE_USED_FOR_REFERENCE | FF_VDPAU_STATE_USED_FOR_RENDER))) { render = vdp->m_videoSurfaces[i]; render->state = 0; break; } } VdpStatus vdp_st = VDP_STATUS_ERROR; if (render == NULL) { // create a new surface VdpDecoderProfile profile; ReadFormatOf(avctx->pix_fmt, profile, vdp->vdp_chroma_type); render = (vdpau_render_state*)calloc(sizeof(vdpau_render_state), 1); vdp_st = vdp->vdp_video_surface_create(vdp->vdp_device, vdp->vdp_chroma_type, avctx->width, avctx->height, &render->surface); vdp->CheckStatus(vdp_st, __LINE__); if (vdp_st != VDP_STATUS_OK) { free(render); CLog::Log(LOGERROR, "CVDPAU::FFGetBuffer - No Video surface available could be created"); return -1; } vdp->m_videoSurfaces.push_back(render); } if (render == NULL) return -1; pic->data[1] = pic->data[2] = NULL; pic->data[0]= (uint8_t*)render; pic->linesize[0] = pic->linesize[1] = pic->linesize[2] = 0; if(pic->reference) { pic->age = pA->ip_age[0]; pA->ip_age[0]= pA->ip_age[1]+1; pA->ip_age[1]= 1; pA->b_age++; } else { pic->age = pA->b_age; pA->ip_age[0]++; pA->ip_age[1]++; pA->b_age = 1; } pic->type= FF_BUFFER_TYPE_USER; render->state |= FF_VDPAU_STATE_USED_FOR_REFERENCE; pic->reordered_opaque= avctx->reordered_opaque; return 0; }
bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) { AVCodec* pCodec; if(!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwScale.Load() || !m_dllAvFilter.Load() ) return false; m_dllAvCodec.avcodec_register_all(); m_dllAvFilter.avfilter_register_all(); m_bSoftware = hints.software; m_iOrientation = hints.orientation; for(std::vector<ERenderFormat>::iterator it = options.m_formats.begin(); it != options.m_formats.end(); ++it) { m_formats.push_back((PixelFormat)CDVDCodecUtils::PixfmtFromEFormat(*it)); if(*it == RENDER_FMT_YUV420P) m_formats.push_back(PIX_FMT_YUVJ420P); } m_formats.push_back(PIX_FMT_NONE); /* always add none to get a terminated list in ffmpeg world */ pCodec = NULL; m_pCodecContext = NULL; if (hints.codec == CODEC_ID_H264) { switch(hints.profile) { case FF_PROFILE_H264_HIGH_10: case FF_PROFILE_H264_HIGH_10_INTRA: case FF_PROFILE_H264_HIGH_422: case FF_PROFILE_H264_HIGH_422_INTRA: case FF_PROFILE_H264_HIGH_444_PREDICTIVE: case FF_PROFILE_H264_HIGH_444_INTRA: case FF_PROFILE_H264_CAVLC_444: m_bSoftware = true; break; } } #ifdef HAVE_LIBVDPAU if(g_guiSettings.GetBool("videoplayer.usevdpau") && !m_bSoftware) { while((pCodec = m_dllAvCodec.av_codec_next(pCodec))) { if(pCodec->id == hints.codec && pCodec->capabilities & CODEC_CAP_HWACCEL_VDPAU) { if ((pCodec->id == CODEC_ID_MPEG4) && !g_advancedSettings.m_videoAllowMpeg4VDPAU) continue; CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Creating VDPAU(%ix%i, %d)",hints.width, hints.height, hints.codec); CVDPAU* vdp = new CVDPAU(); m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec); m_pCodecContext->codec_id = hints.codec; m_pCodecContext->width = hints.width; m_pCodecContext->height = hints.height; m_pCodecContext->coded_width = hints.width; m_pCodecContext->coded_height = hints.height; if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE)) { m_pHardware = vdp; m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set break; } m_dllAvUtil.av_freep(&m_pCodecContext); CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Failed to get VDPAU device"); vdp->Release(); } } } #endif if(pCodec == NULL) pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec); if(pCodec == NULL) { CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to find codec %d", hints.codec); return false; } CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Using codec: %s",pCodec->long_name ? pCodec->long_name : pCodec->name); if(m_pCodecContext == NULL) m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec); m_pCodecContext->opaque = (void*)this; m_pCodecContext->debug_mv = 0; m_pCodecContext->debug = 0; m_pCodecContext->workaround_bugs = FF_BUG_AUTODETECT; m_pCodecContext->get_format = GetFormat; m_pCodecContext->codec_tag = hints.codec_tag; /* Only allow slice threading, since frame threading is more * sensitive to changes in frame sizes, and it causes crashes * during HW accell */ m_pCodecContext->thread_type = FF_THREAD_SLICE; #if defined(TARGET_DARWIN_IOS) // ffmpeg with enabled neon will crash and burn if this is enabled m_pCodecContext->flags &= CODEC_FLAG_EMU_EDGE; #else if (pCodec->id != CODEC_ID_H264 && pCodec->capabilities & CODEC_CAP_DR1 && pCodec->id != CODEC_ID_VP8 ) m_pCodecContext->flags |= CODEC_FLAG_EMU_EDGE; #endif // if we don't do this, then some codecs seem to fail. m_pCodecContext->coded_height = hints.height; m_pCodecContext->coded_width = hints.width; m_pCodecContext->bits_per_coded_sample = hints.bitsperpixel; if( hints.extradata && hints.extrasize > 0 ) { m_pCodecContext->extradata_size = hints.extrasize; m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE); memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize); } // advanced setting override for skip loop filter (see avcodec.h for valid options) // TODO: allow per video setting? if (g_advancedSettings.m_iSkipLoopFilter != 0) { m_pCodecContext->skip_loop_filter = (AVDiscard)g_advancedSettings.m_iSkipLoopFilter; } // set any special options for(std::vector<CDVDCodecOption>::iterator it = options.m_keys.begin(); it != options.m_keys.end(); it++) { if (it->m_name == "surfaces") m_uSurfacesCount = std::atoi(it->m_value.c_str()); else m_dllAvUtil.av_opt_set(m_pCodecContext, it->m_name.c_str(), it->m_value.c_str(), 0); } int num_threads = std::min(8 /*MAX_THREADS*/, g_cpuInfo.getCPUCount()); if( num_threads > 1 && !hints.software && m_pHardware == NULL // thumbnail extraction fails when run threaded && ( pCodec->id == CODEC_ID_H264 || pCodec->id == CODEC_ID_MPEG4 )) m_pCodecContext->thread_count = num_threads; if (m_dllAvCodec.avcodec_open2(m_pCodecContext, pCodec, NULL) < 0) { CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to open codec"); return false; } m_pFrame = m_dllAvCodec.avcodec_alloc_frame(); if (!m_pFrame) return false; UpdateName(); return true; }
bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) { AVCodec* pCodec; if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwScale.Load()) return false; m_dllAvCodec.avcodec_register_all(); m_bSoftware = hints.software; m_pCodecContext = m_dllAvCodec.avcodec_alloc_context(); pCodec = NULL; #ifdef HAVE_LIBVDPAU if(g_guiSettings.GetBool("videoplayer.usevdpau") && !m_bSoftware) { while((pCodec = m_dllAvCodec.av_codec_next(pCodec))) { if(pCodec->id == hints.codec && pCodec->capabilities & CODEC_CAP_HWACCEL_VDPAU) { if ((pCodec->id == CODEC_ID_MPEG4 || pCodec->id == CODEC_ID_XVID) && !g_advancedSettings.m_videoAllowMpeg4VDPAU) continue; CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Creating VDPAU(%ix%i, %d)",hints.width, hints.height, hints.codec); CVDPAU* vdp = new CVDPAU(); m_pCodecContext->codec_id = hints.codec; m_pCodecContext->width = hints.width; m_pCodecContext->height = hints.height; if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE)) { m_pHardware = vdp; m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set break; } m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Failed to get VDPAU device"); vdp->Release(); } } } #endif if(pCodec == NULL) pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec); if(pCodec == NULL) { CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to find codec %d", hints.codec); return false; } CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Using codec: %s",pCodec->long_name ? pCodec->long_name : pCodec->name); m_pCodecContext->opaque = (void*)this; m_pCodecContext->debug_mv = 0; m_pCodecContext->debug = 0; m_pCodecContext->workaround_bugs = FF_BUG_AUTODETECT; m_pCodecContext->get_format = GetFormat; m_pCodecContext->codec_tag = hints.codec_tag; #if defined(__APPLE__) && defined(__arm__) // ffmpeg with enabled neon will crash and burn if this is enabled m_pCodecContext->flags &= CODEC_FLAG_EMU_EDGE; #else if (pCodec->id != CODEC_ID_H264 && pCodec->capabilities & CODEC_CAP_DR1 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,69,0) && pCodec->id != CODEC_ID_VP8 #endif ) m_pCodecContext->flags |= CODEC_FLAG_EMU_EDGE; #endif // if we don't do this, then some codecs seem to fail. m_pCodecContext->coded_height = hints.height; m_pCodecContext->coded_width = hints.width; if( hints.extradata && hints.extrasize > 0 ) { m_pCodecContext->extradata_size = hints.extrasize; m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE); memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize); } // set acceleration m_pCodecContext->dsp_mask = 0;//FF_MM_FORCE | FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE; // advanced setting override for skip loop filter (see avcodec.h for valid options) // TODO: allow per video setting? if (g_advancedSettings.m_iSkipLoopFilter != 0) { m_pCodecContext->skip_loop_filter = (AVDiscard)g_advancedSettings.m_iSkipLoopFilter; } // set any special options for(CDVDCodecOptions::iterator it = options.begin(); it != options.end(); it++) { m_dllAvCodec.av_set_string(m_pCodecContext, it->m_name.c_str(), it->m_value.c_str()); } #if defined(__APPLE__) && defined(__arm__) m_dllAvCodec.avcodec_thread_init(m_pCodecContext, 1); #elif defined(_LINUX) || defined(_WIN32) int num_threads = std::min(8 /*MAX_THREADS*/, g_cpuInfo.getCPUCount()); if( num_threads > 1 && !hints.software && m_pHardware == NULL // thumbnail extraction fails when run threaded && ( pCodec->id == CODEC_ID_H264 || pCodec->id == CODEC_ID_MPEG4 )) m_dllAvCodec.avcodec_thread_init(m_pCodecContext, num_threads); #endif if (m_dllAvCodec.avcodec_open(m_pCodecContext, pCodec) < 0) { CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to open codec"); return false; } m_pFrame = m_dllAvCodec.avcodec_alloc_frame(); if (!m_pFrame) return false; if(pCodec->name) m_name = CStdString("ff-") + pCodec->name; else m_name = "ffmpeg"; if(m_pHardware) m_name += "-" + m_pHardware->Name(); return true; }