首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

LAV Filter 源代码分析 二: LAV Splitter

2013-10-15 
LAV Filter 源代码分析 2: LAV SplitterLAV Filter 中最著名的就是 LAV Splitter,支持Matroska /WebM,MPEG

LAV Filter 源代码分析 2: LAV Splitter

LAV Filter 中最著名的就是 LAV Splitter,支持Matroska /WebM,MPEG-TS/PS,MP4/MOV,FLV,OGM / OGG,AVI等其他格式,广泛存在于各种视频播放器(暴风影音这类的)之中。

本文分析一下它的源代码。在分析之前,先看看它是什么样的。

使用GraphEdit随便打开一个视频文件,就可以看见LAV Filter:

LAV Filter 源代码分析 二: LAV Splitter

可以右键点击这个Filter看一下它的属性页面,如图所示:

属性设置页面:

LAV Filter 源代码分析 二: LAV Splitter

支持输入格式:

LAV Filter 源代码分析 二: LAV Splitter

下面我们在 VC 2010 中看一下它的源代码:

LAV Filter 源代码分析 二: LAV Splitter

从何看起呢?就先从directshow的注册函数看起吧,位于dllmain.cpp之中。部分代码的含义已经用注释标注上了。从代码可以看出,和普通的DirectShow Filter没什么区别。

dllmain.cpp

//初始化AVFormatSTDMETHODIMP CLAVFDemuxer::InitAVFormat(LPCOLESTR pszFileName, BOOL bForce){  HRESULT hr = S_OK;  const char *format = NULL;  //获取InputFormat信息(,短名称,长名称)  lavf_get_iformat_infos(m_avFormat->iformat, &format, NULL);  if (!bForce && (!format || !m_pSettings->IsFormatEnabled(format))) {    DbgLog((LOG_TRACE, 20, L"::InitAVFormat() - format of type '%S' disabled, failing", format ? format : m_avFormat->iformat->name));    return E_FAIL;  }  m_pszInputFormat = format ? format : m_avFormat->iformat->name;  m_bVC1SeenTimestamp = FALSE;  LPWSTR extension = pszFileName ? PathFindExtensionW(pszFileName) : NULL;  m_bMatroska = (_strnicmp(m_pszInputFormat, "matroska", 8) == 0);  m_bOgg = (_strnicmp(m_pszInputFormat, "ogg", 3) == 0);  m_bAVI = (_strnicmp(m_pszInputFormat, "avi", 3) == 0);  m_bMPEGTS = (_strnicmp(m_pszInputFormat, "mpegts", 6) == 0);  m_bMPEGPS = (_stricmp(m_pszInputFormat, "mpeg") == 0);  m_bRM = (_stricmp(m_pszInputFormat, "rm") == 0);  m_bPMP = (_stricmp(m_pszInputFormat, "pmp") == 0);  m_bMP4 = (_stricmp(m_pszInputFormat, "mp4") == 0);  m_bTSDiscont = m_avFormat->iformat->flags & AVFMT_TS_DISCONT;  WCHAR szProt[24] = L"file";  if (pszFileName) {    DWORD dwNumChars = 24;    hr = UrlGetPart(pszFileName, szProt, &dwNumChars, URL_PART_SCHEME, 0);    if (SUCCEEDED(hr) && dwNumChars && (_wcsicmp(szProt, L"file") != 0)) {      m_avFormat->flags |= AVFMT_FLAG_NETWORK;      DbgLog((LOG_TRACE, 10, TEXT("::InitAVFormat(): detected network protocol: %s"), szProt));    }  }  // TODO: make both durations below configurable  // decrease analyze duration for network streams  if (m_avFormat->flags & AVFMT_FLAG_NETWORK || (m_avFormat->flags & AVFMT_FLAG_CUSTOM_IO && !m_avFormat->pb->seekable)) {    // require at least 0.2 seconds    m_avFormat->max_analyze_duration = max(m_pSettings->GetNetworkStreamAnalysisDuration() * 1000, 200000);  } else {    // And increase it for mpeg-ts/ps files    if (m_bMPEGTS || m_bMPEGPS)      m_avFormat->max_analyze_duration = 10000000;  }  av_opt_set_int(m_avFormat, "correct_ts_overflow", !m_pBluRay, 0);  if (m_bMatroska)    m_avFormat->flags |= AVFMT_FLAG_KEEP_SIDE_DATA;  m_timeOpening = time(NULL);  //获取媒体流信息  int ret = avformat_find_stream_info(m_avFormat, NULL);  if (ret < 0) {    DbgLog((LOG_ERROR, 0, TEXT("::InitAVFormat(): av_find_stream_info failed (%d)"), ret));    goto done;  }  DbgLog((LOG_TRACE, 10, TEXT("::InitAVFormat(): avformat_find_stream_info finished, took %I64d seconds"), time(NULL) - m_timeOpening));  m_timeOpening = 0;  // Check if this is a m2ts in a BD structure, and if it is, read some extra stream properties out of the CLPI files  if (m_pBluRay) {    m_pBluRay->ProcessClipLanguages();  } else if (pszFileName && m_bMPEGTS) {    CheckBDM2TSCPLI(pszFileName);  }  SAFE_CO_FREE(m_stOrigParser);  m_stOrigParser = (enum AVStreamParseType *)CoTaskMemAlloc(m_avFormat->nb_streams * sizeof(enum AVStreamParseType));  if (!m_stOrigParser)    return E_OUTOFMEMORY;  for(unsigned int idx = 0; idx < m_avFormat->nb_streams; ++idx) {    AVStream *st = m_avFormat->streams[idx];    // Disable full stream parsing for these formats    if (st->need_parsing == AVSTREAM_PARSE_FULL) {      if (st->codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {        st->need_parsing = AVSTREAM_PARSE_NONE;      }    }    if (m_bOgg && st->codec->codec_id == AV_CODEC_ID_H264) {      st->need_parsing = AVSTREAM_PARSE_FULL;    }    // Create the parsers with the appropriate flags    init_parser(m_avFormat, st);    UpdateParserFlags(st);#ifdef DEBUG    AVProgram *streamProg = av_find_program_from_stream(m_avFormat, NULL, idx);    DbgLog((LOG_TRACE, 30, L"Stream %d (pid %d) - program: %d, codec: %S; parsing: %S;", idx, st->id, streamProg ? streamProg->pmt_pid : -1, avcodec_get_name(st->codec->codec_id), lavf_get_parsing_string(st->need_parsing)));#endif    m_stOrigParser[idx] = st->need_parsing;    if ((st->codec->codec_id == AV_CODEC_ID_DTS && st->codec->codec_tag == 0xA2)     || (st->codec->codec_id == AV_CODEC_ID_EAC3 && st->codec->codec_tag == 0xA1))      st->disposition |= LAVF_DISPOSITION_SECONDARY_AUDIO;    UpdateSubStreams();    if (st->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT && (st->codec->codec_id == AV_CODEC_ID_TTF || st->codec->codec_id == AV_CODEC_ID_OTF)) {      if (!m_pFontInstaller) {        m_pFontInstaller = new CFontInstaller();      }      m_pFontInstaller->InstallFont(st->codec->extradata, st->codec->extradata_size);    }  }  CHECK_HR(hr = CreateStreams());  return S_OK;done:  //关闭输入  CleanupAVFormat();  return E_FAIL;}

该函数通过avformat_find_stream_info()等获取到流信息,这里就不多说了。




热点排行