XBMC分析系列文章:
XBMC源代码分析 4:视频播放器(dvdplayer)-解码器(以ffmpeg为例)
本文我们分析XBMC中视频播放器(dvdplayer)中的解复用器部分。由于解复用器种类很多,不可能一一分析,因此以ffmpeg解复用器为例进行分析。
XBMC解复用器部分文件目录如下图所示:
在这里我们看一下解复用器中的FFMPEG解复用器。对应DVDDemuxFFmpeg.h和DVDDemuxFFmpeg.cpp
之前的分析类文章在解复用器这方面已经做过详细的分析了。在此就不多叙述了,代码很清晰。重点的地方已经标上了注释。
DVDDemuxFFmpeg.h源代码如下所示:
/* * 雷霄骅 * leixiaohua1020@126.com * 中国传媒大学/数字电视技术 * */ #include "DVDDemux.h" #include "DllAvFormat.h" #include "DllAvCodec.h" #include "DllAvUtil.h" #include "threads/CriticalSection.h" #include "threads/SystemClock.h" #include <map> class CDVDDemuxFFmpeg; class CURL; class CDemuxStreamVideoFFmpeg : public CDemuxStreamVideo { CDVDDemuxFFmpeg *m_parent; AVStream* m_stream; public: CDemuxStreamVideoFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream) : m_parent(parent) , m_stream(stream) {} virtual void GetStreamInfo(std::string& strInfo); }; class CDemuxStreamAudioFFmpeg : public CDemuxStreamAudio { CDVDDemuxFFmpeg *m_parent; AVStream* m_stream; public: CDemuxStreamAudioFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream) : m_parent(parent) , m_stream(stream) {} std::string m_description; virtual void GetStreamInfo(std::string& strInfo); virtual void GetStreamName(std::string& strInfo); }; class CDemuxStreamSubtitleFFmpeg : public CDemuxStreamSubtitle { CDVDDemuxFFmpeg *m_parent; AVStream* m_stream; public: CDemuxStreamSubtitleFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream) : m_parent(parent) , m_stream(stream) {} std::string m_description; virtual void GetStreamInfo(std::string& strInfo); virtual void GetStreamName(std::string& strInfo); }; #define FFMPEG_FILE_BUFFER_SIZE 32768 // default reading size for ffmpeg #define FFMPEG_DVDNAV_BUFFER_SIZE 2048 // for dvd's //FFMPEG解复用 class CDVDDemuxFFmpeg : public CDVDDemux { public: CDVDDemuxFFmpeg(); virtual ~CDVDDemuxFFmpeg(); //打开一个流 bool Open(CDVDInputStream* pInput); void Dispose();//关闭 void Reset();//复位 void Flush(); void Abort(); void SetSpeed(int iSpeed); virtual std::string GetFileName(); DemuxPacket* Read(); bool SeekTime(int time, bool backwords = false, double* startpts = NULL); bool SeekByte(int64_t pos); int GetStreamLength(); CDemuxStream* GetStream(int iStreamId); int GetNrOfStreams(); bool SeekChapter(int chapter, double* startpts = NULL); int GetChapterCount(); int GetChapter(); void GetChapterName(std::string& strChapterName); virtual void GetStreamCodecName(int iStreamId, CStdString &strName); bool Aborted(); AVFormatContext* m_pFormatContext; CDVDInputStream* m_pInput; protected: friend class CDemuxStreamAudioFFmpeg; friend class CDemuxStreamVideoFFmpeg; friend class CDemuxStreamSubtitleFFmpeg; int ReadFrame(AVPacket *packet); CDemuxStream* AddStream(int iId); void AddStream(int iId, CDemuxStream* stream); CDemuxStream* GetStreamInternal(int iStreamId); void CreateStreams(unsigned int program = UINT_MAX); void DisposeStreams(); AVDictionary *GetFFMpegOptionsFromURL(const CURL &url); double ConvertTimestamp(int64_t pts, int den, int num); void UpdateCurrentPTS(); bool IsProgramChange(); CCriticalSection m_critSection; std::map<int, CDemuxStream*> m_streams; std::vector<std::map<int, CDemuxStream*>::iterator> m_stream_index; AVIOContext* m_ioContext; //各种封装的Dll DllAvFormat m_dllAvFormat; DllAvCodec m_dllAvCodec; DllAvUtil m_dllAvUtil; double m_iCurrentPts; // used for stream length estimation bool m_bMatroska; bool m_bAVI; int m_speed; unsigned m_program; XbmcThreads::EndTime m_timeout; // Due to limitations of ffmpeg, we only can detect a program change // with a packet. This struct saves the packet for the next read and // signals STREAMCHANGE to player struct { AVPacket pkt; // packet ffmpeg returned int result; // result from av_read_packet }m_pkt; };
该类中以下几个函数包含了解复用器的几个功能。
bool Open(CDVDInputStream* pInput);//打开
void Dispose();//关闭
void Reset();//复位
void Flush();
我们查看一下这几个函数的源代码。
Open()
//打开一个流 bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) { AVInputFormat* iformat = NULL; std::string strFile; m_iCurrentPts = DVD_NOPTS_VALUE; m_speed = DVD_PLAYSPEED_NORMAL; m_program = UINT_MAX; const AVIOInterruptCB int_cb = { interrupt_cb, this }; if (!pInput) return false; if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load()) { CLog::Log(LOGERROR,"CDVDDemuxFFmpeg::Open - failed to load ffmpeg libraries"); return false; } //注册解复用器 // register codecs m_dllAvFormat.av_register_all(); m_pInput = pInput; strFile = m_pInput->GetFileName(); bool streaminfo = true; /* set to true if we want to look for streams before playback*/ if( m_pInput->GetContent().length() > 0 ) { std::string content = m_pInput->GetContent(); /* check if we can get a hint from content */ if ( content.compare("video/x-vobsub") == 0 ) iformat = m_dllAvFormat.av_find_input_format("mpeg"); else if( content.compare("video/x-dvd-mpeg") == 0 ) iformat = m_dllAvFormat.av_find_input_format("mpeg"); else if( content.compare("video/x-mpegts") == 0 ) iformat = m_dllAvFormat.av_find_input_format("mpegts"); else if( content.compare("multipart/x-mixed-replace") == 0 ) iformat = m_dllAvFormat.av_find_input_format("mjpeg"); } // open the demuxer m_pFormatContext = m_dllAvFormat.avformat_alloc_context(); m_pFormatContext->interrupt_callback = int_cb; // try to abort after 30 seconds m_timeout.Set(30000); if( m_pInput->IsStreamType(DVDSTREAM_TYPE_FFMPEG) ) { // special stream type that makes avformat handle file opening // allows internal ffmpeg protocols to be used CURL url = m_pInput->GetURL(); CStdString protocol = url.GetProtocol(); AVDictionary *options = GetFFMpegOptionsFromURL(url); int result=-1; if (protocol.Equals("mms")) { // try mmsh, then mmst url.SetProtocol("mmsh"); url.SetProtocolOptions(""); //真正地打开 result = m_dllAvFormat.avformat_open_input(&m_pFormatContext, url.Get().c_str(), iformat, &options); if (result < 0) { url.SetProtocol("mmst"); strFile = url.Get(); } } //真正地打开 if (result < 0 && m_dllAvFormat.avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0 ) { CLog::Log(LOGDEBUG, "Error, could not open file %s", CURL::GetRedacted(strFile).c_str()); Dispose(); m_dllAvUtil.av_dict_free(&options); return false; } m_dllAvUtil.av_dict_free(&options); } else { unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(FFMPEG_FILE_BUFFER_SIZE); m_ioContext = m_dllAvFormat.avio_alloc_context(buffer, FFMPEG_FILE_BUFFER_SIZE, 0, this, dvd_file_read, NULL, dvd_file_seek); m_ioContext->max_packet_size = m_pInput->GetBlockSize(); if(m_ioContext->max_packet_size) m_ioContext->max_packet_size *= FFMPEG_FILE_BUFFER_SIZE / m_ioContext->max_packet_size; if(m_pInput->Seek(0, SEEK_POSSIBLE) == 0) m_ioContext->seekable = 0; if( iformat == NULL ) { // let ffmpeg decide which demuxer we have to open bool trySPDIFonly = (m_pInput->GetContent() == "audio/x-spdif-compressed"); if (!trySPDIFonly) m_dllAvFormat.av_probe_input_buffer(m_ioContext, &iformat, strFile.c_str(), NULL, 0, 0); // Use the more low-level code in case we have been built against an old // FFmpeg without the above av_probe_input_buffer(), or in case we only // want to probe for spdif (DTS or IEC 61937) compressed audio // specifically, or in case the file is a wav which may contain DTS or // IEC 61937 (e.g. ac3-in-wav) and we want to check for those formats. if (trySPDIFonly || (iformat && strcmp(iformat->name, "wav") == 0)) { AVProbeData pd; uint8_t probe_buffer[FFMPEG_FILE_BUFFER_SIZE + AVPROBE_PADDING_SIZE]; // init probe data pd.buf = probe_buffer; pd.filename = strFile.c_str(); // read data using avformat's buffers pd.buf_size = m_dllAvFormat.avio_read(m_ioContext, pd.buf, m_ioContext->max_packet_size ? m_ioContext->max_packet_size : m_ioContext->buffer_size); if (pd.buf_size <= 0) { CLog::Log(LOGERROR, "%s - error reading from input stream, %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str()); return false; } memset(pd.buf+pd.buf_size, 0, AVPROBE_PADDING_SIZE); // restore position again m_dllAvFormat.avio_seek(m_ioContext , 0, SEEK_SET); // the advancedsetting is for allowing the user to force outputting the // 44.1 kHz DTS wav file as PCM, so that an A/V receiver can decode // it (this is temporary until we handle 44.1 kHz passthrough properly) if (trySPDIFonly || (iformat && strcmp(iformat->name, "wav") == 0 && !g_advancedSettings.m_dvdplayerIgnoreDTSinWAV)) { // check for spdif and dts // This is used with wav files and audio CDs that may contain // a DTS or AC3 track padded for S/PDIF playback. If neither of those // is present, we assume it is PCM audio. // AC3 is always wrapped in iec61937 (ffmpeg "spdif"), while DTS // may be just padded. AVInputFormat *iformat2; iformat2 = m_dllAvFormat.av_find_input_format("spdif"); if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4) { iformat = iformat2; } else { // not spdif or no spdif demuxer, try dts iformat2 = m_dllAvFormat.av_find_input_format("dts"); if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4) { iformat = iformat2; } else if (trySPDIFonly) { // not dts either, return false in case we were explicitely // requested to only check for S/PDIF padded compressed audio CLog::Log(LOGDEBUG, "%s - not spdif or dts file, fallbacking", __FUNCTION__); return false; } } } } if(!iformat) { std::string content = m_pInput->GetContent(); /* check if we can get a hint from content */ if( content.compare("audio/aacp") == 0 ) iformat = m_dllAvFormat.av_find_input_format("aac"); else if( content.compare("audio/aac") == 0 ) iformat = m_dllAvFormat.av_find_input_format("aac"); else if( content.compare("video/flv") == 0 ) iformat = m_dllAvFormat.av_find_input_format("flv"); else if( content.compare("video/x-flv") == 0 ) iformat = m_dllAvFormat.av_find_input_format("flv"); } if (!iformat) { CLog::Log(LOGERROR, "%s - error probing input format, %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str()); return false; } else { if (iformat->name) CLog::Log(LOGDEBUG, "%s - probing detected format [%s]", __FUNCTION__, iformat->name); else CLog::Log(LOGDEBUG, "%s - probing detected unnamed format", __FUNCTION__); } } m_pFormatContext->pb = m_ioContext; if (m_dllAvFormat.avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, NULL) < 0) { CLog::Log(LOGERROR, "%s - Error, could not open file %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str()); Dispose(); return false; } } // Avoid detecting framerate if advancedsettings.xml says so if (g_advancedSettings.m_videoFpsDetect == 0) m_pFormatContext->fps_probe_size = 0; // analyse very short to speed up mjpeg playback start if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0) m_pFormatContext->max_analyze_duration = 500000; // we need to know if this is matroska or avi later m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0; if (streaminfo) { /* too speed up dvd switches, only analyse very short */ if(m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)) m_pFormatContext->max_analyze_duration = 500000; CLog::Log(LOGDEBUG, "%s - avformat_find_stream_info starting", __FUNCTION__); int iErr = m_dllAvFormat.avformat_find_stream_info(m_pFormatContext, NULL); if (iErr < 0) { CLog::Log(LOGWARNING,"could not find codec parameters for %s", CURL::GetRedacted(strFile).c_str()); if (m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD) || m_pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY) || (m_pFormatContext->nb_streams == 1 && m_pFormatContext->streams[0]->codec->codec_id == AV_CODEC_ID_AC3)) { // special case, our codecs can still handle it. } else { Dispose(); return false; } } CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__); } // reset any timeout m_timeout.SetInfinite(); // if format can be nonblocking, let's use that m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; // print some extra information m_dllAvFormat.av_dump_format(m_pFormatContext, 0, strFile.c_str(), 0); UpdateCurrentPTS(); CreateStreams(); return true; }
Dispose()
//关闭 void CDVDDemuxFFmpeg::Dispose() { m_pkt.result = -1; m_dllAvCodec.av_free_packet(&m_pkt.pkt); if (m_pFormatContext) { if (m_ioContext && m_pFormatContext->pb && m_pFormatContext->pb != m_ioContext) { CLog::Log(LOGWARNING, "CDVDDemuxFFmpeg::Dispose - demuxer changed our byte context behind our back, possible memleak"); m_ioContext = m_pFormatContext->pb; } m_dllAvFormat.avformat_close_input(&m_pFormatContext); } if(m_ioContext) { m_dllAvUtil.av_free(m_ioContext->buffer); m_dllAvUtil.av_free(m_ioContext); } m_ioContext = NULL; m_pFormatContext = NULL; m_speed = DVD_PLAYSPEED_NORMAL; DisposeStreams(); m_pInput = NULL; m_dllAvFormat.Unload(); m_dllAvCodec.Unload(); m_dllAvUtil.Unload(); }
Reset()
//复位 void CDVDDemuxFFmpeg::Reset() { CDVDInputStream* pInputStream = m_pInput; Dispose(); Open(pInputStream); }
Flush()
void CDVDDemuxFFmpeg::Flush() { // naughty usage of an internal ffmpeg function if (m_pFormatContext) m_dllAvFormat.av_read_frame_flush(m_pFormatContext); m_iCurrentPts = DVD_NOPTS_VALUE; m_pkt.result = -1; m_dllAvCodec.av_free_packet(&m_pkt.pkt); }
相关推荐
script.bluray.com用于访问 blu-ray.com 功能的 Kodi (XBMC) 插件它目前仅在我的可用。 存储库的安装应通过 Kodi System::Settings::Add-ons::Install from zip 文件完成插件的安装应通过 Kodi System::Settings::...
5. 导航到刚才添加的源,选择“repository.xbmc-addons-chinese-1.2.1.zip”进行安装。 6. 安装完成后,会在“我的添加-ons”中出现新的“仓库”条目,用户可以从这里浏览和安装中文插件。 这个压缩包的使用对于...
4. 更新仓库并安装Red5:`sudo apt-get update && sudo apt-get install red5` 安装完成后,你需要配置Red5服务器,包括设置端口、应用域等。默认情况下,Red5监听1935端口,你可以根据需求修改配置文件。 接下来...
【标题】"ru:seppius-xbmc-repo(叉子)" 指的是一种基于XBMC或Kodi的俄罗斯开发者论坛扩展资源库的克隆版本。XBMC(Xbox Media Center)是一个开源的媒体中心软件,后来更名为Kodi,它允许用户组织和播放各种多媒体...
标题中的"repository.xbmc-addons-chinese-2.0.0.zip"是一个针对KODI媒体中心的中文插件库的压缩包,版本号为2.0.0。这个压缩包包含了多款专为中国用户设计的KODI插件,旨在提升KODI在中文环境下的用户体验和功能...
综上所述,"ffmpeg-2.8.5-Jarvis-rc1.tar.gz" 是为xbmc/kodi开发提供的一个关键的多媒体处理库,包含了一组特定版本的FFmpeg组件,方便开发者快速集成到他们的项目中,以实现多媒体内容的流畅播放。
标题中的“repository.xbmc-addons-chinese-2.0.1.zip”是一个针对Kodi的中文插件库的压缩包,版本号为2.0.1。Kodi是一款开源的媒体中心软件,允许用户在各种设备上管理和播放多媒体内容,如视频、音乐和图片。这个...
kodi中文插件最新2022 repository.xbmc-addons-chinese-2.0.0
"xbmc-forum:XBMC论坛的源代码"这个标题表明我们讨论的是XBMC官方论坛的源代码,这意味着我们可以深入理解其背后的开发过程、社区互动机制以及论坛的构建方式。 源代码通常对开发者来说是非常宝贵的资源,因为它...
XBMC-Trailer-Downloader 抓取 hd-trailers.net 并下载用于 XBMC 和 Cinema Experience 脚本的预告片。 安装:pip install -r requirements.txt 可以以 480/720/1080 的分辨率下载预告片。 可以删除已下载且超过...
XBMC(Xbox Media Center)是一款开源媒体播放器应用,最初为Xbox游戏机开发,后来被移植到了多个操作系统上,包括Android。将XBMC移植到Android平台上需要进行一系列准备工作,包括设置Android开发环境、获取源代码...
它可以帮助您以比以往更少的精力编写播放器。 QtAV已添加到FFmpeg项目页面 QtAV是根据LGPL v2.1条款获得许可的免费软件。 播放器示例已根据GPL v3许可。 如果您使用QtAV或其组成库,则必须遵守相关许可条款。 ...
XBMC-OBD2 是一款基于XBMC(Xbox Media Center,现称为Kodi)平台的开源插件,专为汽车爱好者设计,它允许用户通过ELM327兼容的OBD2诊断适配器获取车辆的实时数据。下面将详细阐述这款插件的功能、工作原理以及如何...
这意味着用户将获得最新的插件和更新,开发者可以在这里找到最新的源代码以进行维护和开发。 通过这个仓库,Kodi用户可以轻松地安装和管理各种中文插件,比如: 1. **中文界面**:提供完全汉化的Kodi界面,让操作...
- **背景**:Medibuntu 是一个额外的软件源,提供了一些不能包含在官方 Ubuntu 发行版中的软件,如多媒体编解码器、专有驱动等。 - **操作步骤**: - 安装 Medibuntu 仓库: ```bash sudo apt-get install ...
解压缩并将文件夹“ plugin.media-type.plugin-name ”重命名为您的插件名称。 在您喜欢的Editor / IDE中将文件夹添加到项目中,然后开始编码! 插件目录结构 去做 贡献 叉吧! 创建功能分支: git checkout -b ...
适用于Kodi(XBMC)的插件幻灯片屏幕保护程序插件-插件中的图像幻灯片 此插件允许使用图片插件作为图片幻灯片屏幕保护程序的源。 安装应该通过Kodi System :: Settings :: Add-ons :: Get Add-Ons :: All Add-Ons :...
在“repository.xbmc-addons-chinese”这个压缩包中,包含了一些为中国用户定制的Kodi插件,尤其是与中文字幕相关的插件。 安装插件的过程如下: 1. **打开Kodi**:启动你的Kodi应用程序,进入主界面。 2. **进入...
xbmc中文插件,不错的,大家可以用一下
标题中的“ubuntu下的kodi(XBMC)编译”指的是在Ubuntu操作系统环境下,对Kodi(以前称为XBMC,Xbox Media Center)媒体中心软件进行源代码编译的过程。Kodi是一款开源的多媒体中心应用,它能播放各种音频、视频格式...