XBMC source code analysis 5: Video Player (dvdplayer)-demultiplexing (taking ffmpeg as an example)

Source: Internet
Author: User

XBMC Analysis Series:

XBMC Source Code Analysis 1: Overall Structure and Compilation Method

XBMC Source Code Analysis 2: Addons (Skin)

XBMC Source Code Analysis 3: core-Overview

XBMC source code analysis 4: Video Player (dvdplayer)-decoder (taking ffmpeg as an example)

In this article, we analyze the demultiplexing section in the XBMC Video Player (dvdplayer. Because there are many types of demultiplexing, it is impossible to analyze them one by one. So we use ffmpeg demultiplexing as an example.

Shows the directory of some XBMC demultiplexing files:

Here, let's take a look at the FFMPEG demultiplexing in the demultiplexing. Corresponding to DVDDemuxFFmpeg. h and DVDDemuxFFmpeg. cpp

The previous analysis articles have made a detailed analysis on the demultiplexing feature. The code is very clear. The key points have been marked with comments.

The source code of DVDDemuxFFmpeg. h is as follows:

/** Leixiao Hua * leixiaohua1020@126.com * China Media University/Digital TV technology **/# 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 {optional * m_parent; AVStream * m_stream; public: CDemuxStreamVideoFFmpeg (CDVDDe MuxFFmpeg * 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: Compute (CDVDDemuxFFmpeg * parent, AVStream * stream): m_parent (parent), m_stream (stream) {} std :: string m_description; virtual void GetStreamIn Fo (std: string & strInfo); virtual void GetStreamName (std: string & strInfo) ;}; class metadata: 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 GetS TreamName (std: string & strInfo );}; # define limit 32768 // default reading size for ffmpeg # define limit 2048 // for dvd's // FFMPEG class CDVDDemuxFFmpeg: public CDVDDemux {public: CDVDDemuxFFmpeg (); virtual ~ CDVDDemuxFFmpeg (); // Open a stream bool Open (CDVDInputStream * pInput); void Dispose (); // disable void Reset (); // 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 program; friend class CDemuxStreamVideoFFmpeg; friend class program; 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; // various encapsulated Dll DllAvFormat m_dllAvFormat; DllAvCodec release; DllAvUtil release; double m_iCurrentPts; // used for stream length estimation bool release; bool m_bAVI; int m_speed; unsigned m_program; usage :: 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 ;};


The following functions in this class include some of the functions of multiplead.

Let's take a look at the source code of these functions.

Open ()

// Open a stream bool ready: Open (CDVDInputStream * pInput) {AVInputFormat * iformat = NULL; std: string strFile; m_iCurrentPts = enabled; 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 the demultiplexing // 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-> Get Content ();/* 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 ("multi Part/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 inter Nal 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 (""); // truly open result = m_dllAvFormat.avformat_open_input (& m_pFormatContext, url. get (). c_str (), iformat, & options); if (result <0) {url. setProtocol ("mmst"); strFile = url. get () ;}// open if (result <0 & m_dllAvFormat.avformat_open_input (& m_pFormatContext, strFile. c_str (), iformat, & options) <0) {CLog: Log (LOGDEBUG, "Error, cocould 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 = buffers (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 * = Bytes/m_ioContext-> max_packet_size; if (m_pInput-> Seek (0, SEEK_POSSIB LE) = 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_packe T_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 proceser 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/pplaydif back. 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 = require ("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, cocould 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; // analyze very short to speed up mjpeg playback start if (iformat & (strcmp (iformat-> name, "mjpeg") = 0) & amp; m_ioContext-& gt; seekable = 0) m_pFormatContext-& gt; 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 analyze 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, "cocould 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 limit (m_pFormatContext, 0, strFile. c_str (), 0); UpdateCurrentPTS (); CreateStreams (); return true ;}

Dispose ()

// Disable 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_ioContext) {CLog: Log (LOGWARNING, "CDVDDemuxFFmpeg: Dispose-demuxer changed our byte context behind our back, possible memleak"); m_ioContext = m_pFormatContext-> pb ;} terminate (& m_pFormatContext);} if (m_ioContext) {m_dllAvUtil.av_free (m_ioContext-> buffer); terminate (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 ()

// 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);}



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.