XBMC分析系列文章:
本文我们分析XBMC中视频播放器(dvdplayer)中的解码器部分。由于解码器种类很多,不可能一一分析,因此以ffmpeg解码器为例进行分析。
XBMC解码器部分文件目录如下图所示:
解码器分为音频解码器和视频解码器。在这里我们看一下视频解码器中的FFMPEG解码器。对应DVDVideoCodecFFmpeg.h和DVDVideoCodecFFmpeg.cpp。
DVDVideoCodecFFmpeg.h源代码如下所示:
/* * 雷霄骅 * leixiaohua1020@126.com * 中国传媒大学/数字电视技术 * */ #include "DVDVideoCodec.h" #include "DVDResource.h" #include "DllAvCodec.h" #include "DllAvFormat.h" #include "DllAvUtil.h" #include "DllSwScale.h" #include "DllAvFilter.h" #include "DllPostProc.h" class CCriticalSection; //封装的FFMPEG视频解码器 class CDVDVideoCodecFFmpeg : public CDVDVideoCodec { public: class IHardwareDecoder : public IDVDResourceCounted<IHardwareDecoder> { public: IHardwareDecoder() {} virtual ~IHardwareDecoder() {}; virtual bool Open (AVCodecContext* avctx, const enum PixelFormat, unsigned int surfaces) = 0; virtual int Decode (AVCodecContext* avctx, AVFrame* frame) = 0; virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture) = 0; virtual int Check (AVCodecContext* avctx) = 0; virtual void Reset () {} virtual unsigned GetAllowedReferences() { return 0; } virtual const std::string Name() = 0; virtual CCriticalSection* Section() { return NULL; } }; CDVDVideoCodecFFmpeg(); virtual ~CDVDVideoCodecFFmpeg(); virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);//打开 virtual void Dispose();//关闭 virtual int Decode(uint8_t* pData, int iSize, double dts, double pts);//解码 virtual void Reset(); bool GetPictureCommon(DVDVideoPicture* pDvdVideoPicture); virtual bool GetPicture(DVDVideoPicture* pDvdVideoPicture); virtual void SetDropState(bool bDrop); virtual unsigned int SetFilters(unsigned int filters); virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open virtual unsigned GetConvergeCount(); virtual unsigned GetAllowedReferences(); bool IsHardwareAllowed() { return !m_bSoftware; } IHardwareDecoder * GetHardware() { return m_pHardware; }; void SetHardware(IHardwareDecoder* hardware) { SAFE_RELEASE(m_pHardware); m_pHardware = hardware; UpdateName(); } protected: static enum PixelFormat GetFormat(struct AVCodecContext * avctx, const PixelFormat * fmt); int FilterOpen(const CStdString& filters, bool scale); void FilterClose(); int FilterProcess(AVFrame* frame); void UpdateName() { if(m_pCodecContext->codec->name) m_name = CStdString("ff-") + m_pCodecContext->codec->name; else m_name = "ffmpeg"; if(m_pHardware) m_name += "-" + m_pHardware->Name(); } AVFrame* m_pFrame; AVCodecContext* m_pCodecContext; CStdString m_filters; CStdString m_filters_next; AVFilterGraph* m_pFilterGraph; AVFilterContext* m_pFilterIn; AVFilterContext* m_pFilterOut; #if defined(LIBAVFILTER_AVFRAME_BASED) AVFrame* m_pFilterFrame; #else AVFilterBufferRef* m_pBufferRef; #endif int m_iPictureWidth; int m_iPictureHeight; int m_iScreenWidth; int m_iScreenHeight; int m_iOrientation;// orientation of the video in degress counter clockwise unsigned int m_uSurfacesCount; //封装Dll的各种类 DllAvCodec m_dllAvCodec; DllAvUtil m_dllAvUtil; DllSwScale m_dllSwScale; DllAvFilter m_dllAvFilter; DllPostProc m_dllPostProc; std::string m_name; bool m_bSoftware; bool m_isHi10p; IHardwareDecoder *m_pHardware; int m_iLastKeyframe; double m_dts; bool m_started; std::vector<PixelFormat> m_formats; };
该类中以下几个函数包含了解码器的几种功能:
virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);//打开
virtual void Dispose();//关闭
virtual int Decode(uint8_t* pData, int iSize, double dts, double pts);//解码
virtual void Reset();//复位
为了说明这一点,我们可以看一下视频解码器中的libmpeg2解码器,对应DVDVideoCodecLibMpeg2.h。可以看出这几个函数是一样的。
DVDVideoCodecLibMpeg2.h源代码如下:
/* * 雷霄骅 * leixiaohua1020@126.com * 中国传媒大学/数字电视技术 * */ #include "DVDVideoCodec.h" #include "DllLibMpeg2.h" class CDVDVideoCodecLibMpeg2 : public CDVDVideoCodec { public: CDVDVideoCodecLibMpeg2(); virtual ~CDVDVideoCodecLibMpeg2(); virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); virtual void Dispose(); virtual int Decode(uint8_t* pData, int iSize, double dts, double pts); virtual void Reset(); virtual bool GetPicture(DVDVideoPicture* pDvdVideoPicture); virtual bool GetUserData(DVDVideoUserData* pDvdVideoUserData); virtual void SetDropState(bool bDrop); virtual const char* GetName() { return "libmpeg2"; } protected: DVDVideoPicture* GetBuffer(unsigned int width, unsigned int height); inline void ReleaseBuffer(DVDVideoPicture* pPic); inline void DeleteBuffer(DVDVideoPicture* pPic); static int GuessAspect(const mpeg2_sequence_t *sequence, unsigned int *pixel_width, unsigned int *pixel_height); mpeg2dec_t* m_pHandle; const mpeg2_info_t* m_pInfo; DllLibMpeg2 m_dll; unsigned int m_irffpattern; bool m_bFilm; //Signals that we have film material bool m_bIs422; int m_hurry; double m_dts; double m_dts2; //The buffer of pictures we need DVDVideoPicture m_pVideoBuffer[3]; DVDVideoPicture* m_pCurrentBuffer; };
现在回到DVDVideoCodecFFmpeg.h。我们可以看一下上文所示的4个函数。
Open()
//打开 bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) { AVCodec* pCodec; if(!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwScale.Load() || !m_dllPostProc.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 == AV_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: // this is needed to not open the decoders m_bSoftware = true; // this we need to enable multithreading for hi10p via advancedsettings m_isHi10p = true; break; } } //查找解码器 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 - so we unset it in this case. * * When we detect Hi10p and user did not disable hi10pmultithreading * via advancedsettings.xml we keep the ffmpeg default thread type. * */ if(m_isHi10p && !g_advancedSettings.m_videoDisableHi10pMultithreading) { CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Keep default threading for Hi10p: %d", m_pCodecContext->thread_type); } else if (CSettings::Get().GetBool("videoplayer.useframemtdec")) { CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Keep default threading %d by videoplayer.useframemtdec", m_pCodecContext->thread_type); } else 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 != AV_CODEC_ID_H264 && pCodec->capabilities & CODEC_CAP_DR1 && pCodec->id != AV_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 == AV_CODEC_ID_H264 || pCodec->id == AV_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; } //初始化AVFrame m_pFrame = m_dllAvCodec.avcodec_alloc_frame(); if (!m_pFrame) return false; #if defined(LIBAVFILTER_AVFRAME_BASED) m_pFilterFrame = m_dllAvUtil.av_frame_alloc(); if (!m_pFilterFrame) return false; #endif UpdateName(); return true; }
Dispose()
//关闭 void CDVDVideoCodecFFmpeg::Dispose() { //释放 if (m_pFrame) m_dllAvUtil.av_free(m_pFrame); m_pFrame = NULL; #if defined(LIBAVFILTER_AVFRAME_BASED) m_dllAvUtil.av_frame_free(&m_pFilterFrame); #endif if (m_pCodecContext) { //关闭解码器 if (m_pCodecContext->codec) m_dllAvCodec.avcodec_close(m_pCodecContext); if (m_pCodecContext->extradata) { m_dllAvUtil.av_free(m_pCodecContext->extradata); m_pCodecContext->extradata = NULL; m_pCodecContext->extradata_size = 0; } m_dllAvUtil.av_free(m_pCodecContext); m_pCodecContext = NULL; } SAFE_RELEASE(m_pHardware); FilterClose(); m_dllAvCodec.Unload(); m_dllAvUtil.Unload(); m_dllAvFilter.Unload(); m_dllPostProc.Unload(); }
Decode()
//解码 int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double pts) { int iGotPicture = 0, len = 0; if (!m_pCodecContext) return VC_ERROR; if(pData) m_iLastKeyframe++; shared_ptr<CSingleLock> lock; if(m_pHardware) { CCriticalSection* section = m_pHardware->Section(); if(section) lock = shared_ptr<CSingleLock>(new CSingleLock(*section)); int result; if(pData) result = m_pHardware->Check(m_pCodecContext); else result = m_pHardware->Decode(m_pCodecContext, NULL); if(result) return result; } if(m_pFilterGraph) { int result = 0; if(pData == NULL) result = FilterProcess(NULL); if(result) return result; } m_dts = dts; m_pCodecContext->reordered_opaque = pts_dtoi(pts); //初始化AVPacket AVPacket avpkt; m_dllAvCodec.av_init_packet(&avpkt); avpkt.data = pData; avpkt.size = iSize; /* We lie, but this flag is only used by pngdec.c. * Setting it correctly would allow CorePNG decoding. */ avpkt.flags = AV_PKT_FLAG_KEY; //解码 len = m_dllAvCodec.avcodec_decode_video2(m_pCodecContext, m_pFrame, &iGotPicture, &avpkt); if(m_iLastKeyframe < m_pCodecContext->has_b_frames + 2) m_iLastKeyframe = m_pCodecContext->has_b_frames + 2; if (len < 0) { CLog::Log(LOGERROR, "%s - avcodec_decode_video returned failure", __FUNCTION__); return VC_ERROR; } if (!iGotPicture) return VC_BUFFER; if(m_pFrame->key_frame) { m_started = true; m_iLastKeyframe = m_pCodecContext->has_b_frames + 2; } /* put a limit on convergence count to avoid huge mem usage on streams without keyframes */ if(m_iLastKeyframe > 300) m_iLastKeyframe = 300; /* h264 doesn't always have keyframes + won't output before first keyframe anyway */ if(m_pCodecContext->codec_id == AV_CODEC_ID_H264 || m_pCodecContext->codec_id == AV_CODEC_ID_SVQ3) m_started = true; if(m_pHardware == NULL) { bool need_scale = std::find( m_formats.begin() , m_formats.end() , m_pCodecContext->pix_fmt) == m_formats.end(); bool need_reopen = false; if(!m_filters.Equals(m_filters_next)) need_reopen = true; if(m_pFilterIn) { if(m_pFilterIn->outputs[0]->format != m_pCodecContext->pix_fmt || m_pFilterIn->outputs[0]->w != m_pCodecContext->width || m_pFilterIn->outputs[0]->h != m_pCodecContext->height) need_reopen = true; } // try to setup new filters if (need_reopen || (need_scale && m_pFilterGraph == NULL)) { m_filters = m_filters_next; if(FilterOpen(m_filters, need_scale) < 0) FilterClose(); } } int result; if(m_pHardware) result = m_pHardware->Decode(m_pCodecContext, m_pFrame); else if(m_pFilterGraph) result = FilterProcess(m_pFrame); else result = VC_PICTURE | VC_BUFFER; if(result & VC_FLUSHED) Reset(); return result; }
Reset()
//复位 void CDVDVideoCodecFFmpeg::Reset() { m_started = false; m_iLastKeyframe = m_pCodecContext->has_b_frames; m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext); if (m_pHardware) m_pHardware->Reset(); m_filters = ""; FilterClose(); }
相关推荐
script.bluray.com用于访问 blu-ray.com 功能的 Kodi (XBMC) 插件它目前仅在我的可用。 存储库的安装应通过 Kodi System::Settings::Add-ons::Install from zip 文件完成插件的安装应通过 Kodi System::Settings::...
3. 输入路径(例如,如果文件在USB驱动器上,路径可能是“设备>\repository.xbmc-addons-chinese”),然后给源命名。 4. 返回主菜单,进入“程序”>“添加-ons”>“我的添加-ons”>“安装从zip文件”。 5. 导航到...
综上所述,"ffmpeg-2.8.5-Jarvis-rc1.tar.gz" 是为xbmc/kodi开发提供的一个关键的多媒体处理库,包含了一组特定版本的FFmpeg组件,方便开发者快速集成到他们的项目中,以实现多媒体内容的流畅播放。
标题中的"repository.xbmc-addons-chinese-2.0.0.zip"是一个针对KODI媒体中心的中文插件库的压缩包,版本号为2.0.0。这个压缩包包含了多款专为中国用户设计的KODI插件,旨在提升KODI在中文环境下的用户体验和功能...
"xbmc-forum:XBMC论坛的源代码"这个标题表明我们讨论的是XBMC官方论坛的源代码,这意味着我们可以深入理解其背后的开发过程、社区互动机制以及论坛的构建方式。 源代码通常对开发者来说是非常宝贵的资源,因为它...
【标题】"ru:seppius-xbmc-repo(叉子)" 指的是一种基于XBMC或Kodi的俄罗斯开发者论坛扩展资源库的克隆版本。XBMC(Xbox Media Center)是一个开源的媒体中心软件,后来更名为Kodi,它允许用户组织和播放各种多媒体...
如果你没有这个工具,可以自行编译或从源代码构建。 使用rtmpdump向Red5推送AAC流的命令通常会包括以下参数: ``` rtmpdump -r "rtmp://your-server-address/your-app/stream-name" -v -a "your-aac-stream-file....
它可以帮助您以比以往更少的精力编写播放器。 QtAV已添加到FFmpeg项目页面 QtAV是根据LGPL v2.1条款获得许可的免费软件。 播放器示例已根据GPL v3许可。 如果您使用QtAV或其组成库,则必须遵守相关许可条款。 ...
XBMC(Xbox Media Center)是一款开源媒体播放器应用,最初为Xbox游戏机开发,后来被移植到了多个操作系统上,包括Android。将XBMC移植到Android平台上需要进行一系列准备工作,包括设置Android开发环境、获取源代码...
标题中的“repository.xbmc-addons-chinese-2.0.1.zip”是一个针对Kodi的中文插件库的压缩包,版本号为2.0.1。Kodi是一款开源的媒体中心软件,允许用户在各种设备上管理和播放多媒体内容,如视频、音乐和图片。这个...
kodi中文插件最新2022 repository.xbmc-addons-chinese-2.0.0
XBMC-OBD2 是一款基于XBMC(Xbox Media Center,现称为Kodi)平台的开源插件,专为汽车爱好者设计,它允许用户通过ELM327兼容的OBD2诊断适配器获取车辆的实时数据。下面将详细阐述这款插件的功能、工作原理以及如何...
XBMC-Trailer-Downloader 抓取 hd-trailers.net 并下载用于 XBMC 和 Cinema Experience 脚本的预告片。 安装:pip install -r requirements.txt 可以以 480/720/1080 的分辨率下载预告片。 可以删除已下载且超过...
sudo apt-get install non-free-codecs libxine1-ffmpeg gxinemencoder libmpcdec3 libquicktime1 flac faac faad sox ffmpeg2theora libmpeg2-4 uudeview flac libmpeg3-1 mpeg3-utils mpg321 mpg123 libflac++6 ...
这意味着用户将获得最新的插件和更新,开发者可以在这里找到最新的源代码以进行维护和开发。 通过这个仓库,Kodi用户可以轻松地安装和管理各种中文插件,比如: 1. **中文界面**:提供完全汉化的Kodi界面,让操作...
适用于Kodi(XBMC)的插件幻灯片屏幕保护程序插件-插件中的图像幻灯片 此插件允许使用图片插件作为图片幻灯片屏幕保护程序的源。 安装应该通过Kodi System :: Settings :: Add-ons :: Get Add-Ons :: All Add-Ons :...
在“repository.xbmc-addons-chinese”这个压缩包中,包含了一些为中国用户定制的Kodi插件,尤其是与中文字幕相关的插件。 安装插件的过程如下: 1. **打开Kodi**:启动你的Kodi应用程序,进入主界面。 2. **进入...
Kodi(XBMC)插件样板 目录结构,包含操作Kodi(XBMC)附加组件所需的所有资源。 用法 。 解压缩并将文件夹“ plugin.media-type.plugin-name ”重命名为您的插件名称。 在您喜欢的Editor / IDE中将文件夹添加到...
标题中的“ubuntu下的kodi(XBMC)编译”指的是在Ubuntu操作系统环境下,对Kodi(以前称为XBMC,Xbox Media Center)媒体中心软件进行源代码编译的过程。Kodi是一款开源的多媒体中心应用,它能播放各种音频、视频格式...
xbmc中文插件,不错的,大家可以用一下