DirectShow開發快速入門之慨述

文章來源:http://tech.163.com/school · 2005-08-18 10:21:32 · 來源: 天極網
摘要:本篇文檔概括性的介紹了DirectShow的主要組成部分,以及一些Directshow的基本概念。熟悉這些基本的知識對于Directshow的應用開發或者過濾器的開發者都會有所幫助。

  DirectShow是微軟公司提供的一套在Windows平臺上進行流媒體處理的開發包,與DirectX開發包一起發布。那么,DirectShow能夠做些什么呢?且看,DirectShow為多媒體流的捕捉和回放提供了強有力的支持。運用DirectShow,我們可以很方便地從支持WDM驅動模型的采集卡上捕獲數據,并且進行相應的后期處理乃至存儲到文件中。它廣泛地支持各種媒體格式,包括Asf、Mpeg、Avi、Dv、Mp3、Wave等等,使得多媒體數據的回放變得輕而易舉。另外,DirectShow還集成了DirectX其它部分(比如DirectDraw、DirectSound)的技術,直接支持DVD的播放,視頻的非線性編輯,以及與數字攝像機的數據交換。更值得一提的是,DirectShow提供的是一種開放式的開發環境,我們可以根據自己的需要定制自己的組件。

  應用程序與DirectShow組件以及DirectShow所支持的軟硬件之間的關系如圖1所示。

DirectShow開發快速入門之慨述(一)
圖1 DirectShow系統框圖

  1、DirectShow的 Filter

  Directshow是基于模塊化,每個功能模塊都采取COM組件方式,稱為Filter。Directshow提供了一系列的標準的模塊可用于應用開發,開發者也可以開發自己的功能Filter來擴展Directshow的應用。下面我們用一個例子來說明如何采取Filter來播放一個AVI的視頻文件。

  1) 首先從一個文件中讀取AVI數據,形成字節流。(這個工作由源Filter完成)

  2) 檢查AVI數據流的頭格式,然后通過AVI分割Filter將視頻流和音頻流分開。

  3) 解碼視頻流,根據壓縮格式的不同,選取不同的decoder filters 。

  4) 通過Renderer Filter重畫視頻 圖像

  5) 音頻流送到聲卡進行播放,一般采用缺省的 DirectSound DeviceFilter。流程見下圖。

DirectShow開發快速入門之慨述(一)
圖2 音頻流播放Graph圖

  從上面的圖表看,每一個filter都一個其他的一個或者兩個filter相連接。兩個Filter相連接的連接點也是com對象,我們稱為Pin。 Filter通過pin將數據從一個filter傳遞到另一個filter中,從而可以使數據在由filter組成的鏈表中流動。圖中的箭頭表示 filter鏈表中的數據流的方向。在Directshow中,像上面的這樣一個filter 鏈表我們稱為filter Graph。

  Filter具有三個狀態,運行,停止,暫停。當一個filter運行時,它就處理媒體數據流,當停止時,filter就不在處理數據,暫停狀態常用來給運行狀態之前cure data。Data Flow in the Filter Graph一章詳細描述了這些概念,可以參考。

  除了一些特別的例外, Filter graph中所有的filter的狀態的改變都是統一的,也就說,filte graph中的所有的filter 的狀態改變是一致協調的。也就是說,我們也可以用filter graph也可以有運行,停止,暫停三種狀態。

  Filter 一般分為下面幾種類型。

  (1)源過濾器( sourcefilter):源過濾器引入數據到過濾器圖表中,數據來源可以是文件、網絡、 照相機等。不同的源過濾器處理不同類型的數據源。

  (2)變換過濾器(transform filter):變換過濾器的工作是獲取輸入流,處理數據,并生成輸出流。變換過濾器對數據的處理包括 編解碼、格式轉換、壓縮解壓縮等。

  (3)提交過濾器(renderer filter):提交過濾器在過濾器圖表里處于最后 一級,它們接收數據并把數據提交給外設。

  (4)分割過濾器(splitter filter):分割過濾器把輸入流分割成多個輸出。例如,AVI分割過濾器把一個AVI格式的字節流分割成視頻流和音頻流。

  (5)混合過濾器(mux filter):混合過濾器把多個輸入組合成一個單獨的數據流。例如,AVI混合過濾器把視頻流和音頻流合成一個AVI格式的字節流。

  過濾器的這些分類并不是絕對的,例如一個ASF讀過濾器(ASF Reader filter)既是一個源過濾器又是一個分割過濾器。

  2、關于Filter Graph Manager

  Filter Graph Manager也是一個com對象,用來控制Filter graph中的所有的filter,主要有以下的功能:

  1) 用來協調filter之間的狀態改變,從而使graph 中的所有的filter的狀態的改變應該一致。

  2) 建立一個參考時鐘。

  3) 將filter 的消息通知返回給應用程序

  4) 提供用來建立 filter graph的方法。

  這里只是簡單的描述一下,詳細地可以參考文檔。

  狀態改變,Graph中的filter的狀態改變應該一致,因此,應用程序并將狀態改變的命令直接發給filter,而是將相應的狀態改變的命令發送給 Filter graph Manager,由manager將命令分發給graph中每一個filter。Seeking也是同樣的方式工作,首先由應用程序將seek命令發送到 filter graph 管理器,然后由其分發給每個filter。

  參考時鐘,graph中的filter都采用的同一個時鐘,稱 為參考時鐘(reference clock),參考時鐘可以確保所有的數據流同步,視頻楨或者音頻楨應該被提交的時間稱為presentation time.presentation time 是相對于參考時鐘來確定的。Filter graph Manager應該選擇一個參考時鐘,可以選擇聲卡上的時鐘,也可以選擇系統時鐘。

  Graph事件, Graph 管理器采用事件機制將graph中發生的事件通知給應用程序,這個機制類似于 windows的消息循環機制。

  Graph構建的方法,graph管理器給應用程序提供了將filter添加進graph的方法,連接filter的方法,斷開filter連接的方法。

  但是,graph 管理器沒有提供如何將數據從一個filter發送到另一個filter的方法,這個工作是由filter在內部通過pin來獨立完成的,

3、媒體類型

  因為Directshow是基于com組件的,就需要有一種方式來描述filter graph每一個點的數據格式,例如,我們還以播放AVI文件為例,數據以RIFF塊的形式進入graph中,然后被分割成視頻和音頻流,視頻流有一系列的壓縮的視頻楨組成,解壓后,視頻流由一系列的無壓縮的位圖組成,音頻流也要走同樣的步驟。

Media Types: How DirectShow Represents Formats
  媒體類型是一種很普遍的,可以擴展的用來描述數字媒體格式的方法,當兩個filter連接的時候,他們會就采用某一種媒體類型達成一致的協議。媒體類型定義了處于源頭的filter將要給下游的filter發送什么樣的數據,以及數據的physical layout。如果兩個filter不能夠支持同一種的媒體類型,那么他們就沒法連接起來。

  對于大多數的應用來說,也許你不用考慮媒體類型,但是,有些應用程序中,你會直接應用到媒體類型的。

  媒體類型是通過AM_MEDIA_TYPE結構定義的,看看原始定義吧

typedef struct _MediaType {
  GUID majortype;
  GUID subtype;
  BOOL bFixedSizeSamples;
  BOOL bTemporalCompression;
  ULONG lSampleSize;
  GUID formattype;
  IUnknown *pUnk;
  ULONG cbFormat;
  [size_is(cbFormat)] BYTE *pbFormat;
} AM_MEDIA_TYPE;

  Major type:是一個GUID,用來定義數據的主類型,包括,音頻,視頻,unparsed字節流,MIDI數據,等等,具體可以參考msdn。

   Subtype:子類型,也是一個GUID,用來進一步的細化數據格式,例如,在視頻主類型中,還包括RGB-24, RGB-32, UYVY等等一些子類型,在音頻主類型中還包括PCM audio, MPEG-1 payload等類型,子類型提供了比主類型更詳細的信息,但是并沒有定義所有的格式,例如,視頻的子類型并沒有定義圖像大小,楨率。這些由下面的字段定義。

  bFixedSizeSamples當這個值為TRUE時,表示sample大小固定。

  bTemporalCompression當這個值為TRUE時,表示sample采用了臨時壓縮格式,表明不是所有的楨都是關鍵楨,如果為FALSE,表明所有的都是關鍵楨。

  lSampleSize 表示sample的大小。對于壓縮的數據,這個值可能為零。
  
   Formattype一個GUID值,用來表明內存塊的格式。包括如下:FORMAT_None,FORMAT_DvInfo,FORMAT_MPEGVideo,FORMAT_MPEG2Video,FORMAT_VideoInfo,FORMAT_VideoInfo2,FORMAT_WaveFormatEx,GUID_NULL。

  pUnk該參數沒有用到。

  cbFormat內存塊的大小。

  pbFormat指向內存塊的指針。

  下面我們看一段代碼,看看filter如何檢測媒體類型的。

HRESULT CheckMediaType(AM_MEDIA_TYPE *pmt)
{
  if (pmt == NULL) return E_POINTER;
  // Check the major type. We’re looking for video.
  if (pmt->majortype != MEDIATYPE_Video)
  {
   return VFW_E_INVALIDMEDIATYPE;
  }
  // Check the subtype. We’re looking for 24-bit RGB.
  if (pmt->subtype != MEDIASUBTYPE_RGB24)
  {
   return VFW_E_INVALIDMEDIATYPE;
  }
  // Check the format type and the size of the format block.
  if ((pmt->formattype == FORMAT_VideoInfo) && (pmt->cbFormat >= sizeof(VIDEOINFOHEADER) &&
(pmt->pbFormat != NULL))
  {
   // Now it’s safe to coerce the format block pointer to the
   // correct structure, as defined by the formattype GUID.
   VIDEOINFOHEADER *pVIH = (VIDEOINFOHEADER*)pmt->pbFormat;
   // Examine pVIH (not shown). If it looks OK, return S_OK.
   return S_OK;
  }
  return VFW_E_INVALIDMEDIATYPE;
}

  下面簡單介紹幾個和 Media Type相關的函數:

  AM_MEDIA_TYPE結構包含一個指向數據塊的指針,因此,當你使用這個結構的時候,一定要小心內存分配,以防內存泄漏。

  分配函數

  1) AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc );

  這個函數分配一個新的AM_MEDIA_TYPE結構,包含特定格式的數據塊。釋放由這個函數分配的內存,可以調用DeleteMediaType函數

  2) STDAPI CreateAudioMediaType(const WAVEFORMATEX *pwfx,AM_MEDIA_TYPE *pmt,BOOL bSetFormat);

  該函數利用一個給定的WAVEFORMATIEX結構來初始化媒體類型,如果bsetFormat參數為TRUE,該函數就分配一塊新的內存,如果原來的pmt已經包含內存,就有可能發生內存泄漏。為了避免內存泄漏,在調用這個函數前要調用FreeMediaType(),在這個函數返回之后,再次調用 FreeMediaType(),釋放format block。

  3) HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget,const AM_MEDIA_TYPE *pmtSource);

  這個函數復制了一個結構到另一個結構中去。這個函數也要重新分配內存給目的結構,如果pmtTarget,已經包含一個內存塊,就要內存泄漏,因此,在調用該函數前后都要調用FreeMediaType函數。

  釋放函數

  4) void WINAPI DeleteMediaType( AM_MEDIA_TYPE *pmt);

  無論是采用CoTaskMemAlloc函數還是用CreateMediaType函數分配的內存都可以用這個函數來釋放,如果你沒有連接基類的動態庫,你可以用下面的代碼

void MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
{
  if (pmt != NULL)
  {
   MyFreeMediaType(*pmt); // 見下面的 FreeMediaType 函數
   CoTaskMemFree(pmt);
  }
}

  5) void WINAPI FreeMediaType( AM_MEDIA_TYPE& mt);

  這個函數用來釋放數據塊的內存,如果要刪除AM_MEDIA_TYPE結構,可以使用DeleteMediaType函數。

void MyFreeMediaType(AM_MEDIA_TYPE& mt)
{
  if (mt.cbFormat != 0)
  {
   CoTaskMemFree((PVOID)mt.pbFormat);
   mt.cbFormat = 0;
   mt.pbFormat = NULL;
  }
  if (mt.pUnk != NULL)
  {
   // Unecessary because pUnk should not be used, but safest.
   mt.pUnk->Release();
   mt.pUnk = NULL;
  }
}

4、媒體Samples和Allocators

  Filters通過pin的連接來傳遞數據,數據流是從一個filter的輸出pin流向相連的filter的輸入pin。輸出pin常用的傳遞數據的方式是調用輸入pin上的IMemInputPin::Receive方法。

  對于filter來說,可以有好幾種方式來分配媒體數據使用的內存塊,可以在堆上分配,可以在DirectDraw的表面,也可以采用GDI共享內存,還有其他的一些方法,在Directshow中用來進行內存分配任務的是內存分配器(allocator),也是一個COM對象,暴露了一個 IMemAllocator接口。

  當兩個pin連接的時候,必須有一個pin提供一個allocator,Directshow定義了一系列函數調用用來確定由哪個pin提供allocator,以及buffer的數量和大小。

   在數據流開始之前,allocator會創建一個內存池(pool of buffer),在開始發送數據流以后,源filter就會將數據填充到內存池中一個空閑的buffer中,然后傳遞給下面的filter。但是,源 filter并不是直接將內存buffer的指針直接傳遞給下游的filter,而是通過一個media samples的COM對象,這個sample是allocator創建的用來管理內存buffer。Media sample暴露了IMediaSample接口,一個sample包含了下面的內容:

  一個指向沒有發送的內存的指針。

  一個時間戳

  一些標志

  媒體類型。

   時間戳表明了presentation time,Renderer filter就是根據這個時間來安排render順序的。標志是用來標示數據是否中斷等等,媒體類型提供了中途改變數據格式的一種方法,不過,一般 sample沒有媒體類型,表明它們的媒體類型一直沒有改變。

  當一個filter正在使用buffer,它就會保持一個sample 的引用計數,allocator通過sample的引用計數用來確定是否可以重新使用一個buffer。這樣就防止了buffer的使用沖突,當所有的 filter都釋放了對sample的引用,sample才返回到allocator的內存池,供重新使用。

  5、硬件設備在graph中的作用

  下面的這段話借用的是陸其明的一段文檔,特此標記2005-1-26我覺得他對硬件的表述比較清楚。

  大家知道,為了提高系統的穩定性,Windows操作系統對硬件操作進行了隔離;應用程序一般不能直接訪問硬件。DirectShow Filter工作在用戶模式(User mode,操作系統特權級別為Ring 3),而硬件工作在內核模式(Kernel mode,操作系統特權級別為Ring 0),那么它們之間怎么協同工作呢?

  DirectShow解決的方法是,為這些硬件設計包裝Filter;這種Filter能夠工作在用戶模式下,外觀、控制方法跟普通Filter一樣,而包裝Filter內部完成與硬件驅動程序的交互。這樣的設計,使得編寫DirectShow應用程序的開發人員,從為支持硬件而需做出的特殊處理中解脫出來。DirectShow已經集成的包裝Filter,包括Audio Capture Filter(qcap.dll)、VfW Capture Filter(qcap.dll,Filter的Class Id為CLSID_VfwCapture)、TV Tuner Filter(KSTVTune.ax,Filter的Class Id為CLSID_CTVTunerFilter)、Analog Video Crossbar Filter(ksxbar.ax)、TV Audio Filter(Filter的Class Id為CLSID_TVAudioFilter)等;另外,DirectShow為采用WDM驅動程序的硬件設計了KsProxy Filter(Ksproxy.ax,)。我們可以看一下結構圖:見圖1

  我們可以看出,Ksproxy.ax、Kstune.ax、 Ksxbar.ax這些包裝Filter跟其它普通的DirectShow Filter處于同一個級別,可以協同工作;用戶模式下的Filter通過Stream Class控制硬件的驅動程序minidriver(由硬件廠商提供的實現對硬件控制功能的DLL);Stream Class和minidriver一起向上層提供系統底層級別的服務。值得注意的是,這里的Stream Class是一種驅動模型,它負責調用硬件的minidriver;另外,Stream Class的功能還在于協調minidriver之間的工作,使得一些數據可以直接在Kernel mode下從一個硬件傳輸到另一個硬件(或同一個硬件上的不同功能模塊),提高了系統的工作效率。(更多的關于底層驅動程序的細節,請讀者參閱 Windows DDK。)

  下面,我們分別來看一下幾種常見的硬件。

  VfW視頻采集卡。這類硬件在市場上已經處于一種淘汰的趨勢;新生產的視頻采集卡一般采用WDM驅動模型。但是,DirectShow為了保持向后兼容,還是專門提供了一個包裝Filter支持這種硬件。和其他硬件的包裝Filter一樣,這種包裝Filter的創建不是像普通Filter一樣使用CoCreateInstance,而要通過系統枚舉,然后BindToObject。

  音頻采集卡(聲卡)。聲卡的采集功能也是通過包裝Filter來實現的;而且現在的聲卡大部分都有混音的功能。這個Filter一般有幾個Input pin,每個pin都代表一個輸入,如Line In、Microphone、CD、MIDI等。值得注意的是,這些pin代表的是聲卡上的物理輸入端子,在Filter Graph中是永遠不會連接到其他Filter上的。聲卡的輸出功能,可以有兩個Filter供選擇:DirectSound Renderer Filter和Audio Renderer (WaveOut) Filter。注意,這兩個Filter不是上述意義上的包裝Filter,它們能夠同硬件交互,是因為它們使用了API函數:前者使用了 DirectSound API,后者使用了waveOut API。這兩個Filter的區別,還在于后者輸出音頻的同時不支持混音。(順便說明一下,Video Renderer Filter能夠訪問顯卡,也是因為使用了GDI、DirectDraw或Direct3D API。)如果你的機器上有聲卡的話,你可以通過GraphEdit,在Audio Capture Sources目錄下看到這個聲卡的包裝Filter。

  WDM驅動的硬件(包括視頻捕捉卡、硬件解壓卡等)。這類硬件都使用 Ksproxy.ax這個包裝Filter。Ksproxy.ax實現了很多功能,所以有“瑞士軍刀”的美譽;它還被稱作為“變色龍Filter”,因為該Filter上定義了統一的接口,而接口的實現因具體的硬件驅動程序而異。在Filter Graph中,Ksproxy Filter顯示的名字為硬件的Friendly name(一般在驅動程序的.inf文件中定義)。我們可以通過GraphEdit,在WDM Streaming開頭的目錄中找到本機系統中安裝的WDM硬件。因為KsProxy.ax能夠代表各種WDM的音視頻設備,所以這個包裝Filter的工作流程有點復雜。這個Filter不會預先知道要代表哪種類型的設備,它必須首先訪問驅動程序的屬性集,然后動態配置Filter上應該實現的接口。

   當Ksproxy Filter上的接口方法被應用程序或其他Filter調用時,它會將調用方法以及參數傳遞給驅動程序,由驅動程序最終完成指定功能。除此以外,WDM硬件還支持內核流(Kernel Streaming),即內核模式下的數據傳輸,而無需經過到用戶模式的轉換。因為內核模式與用戶模式之間的相互轉換,需要花費很大的計算量。如果使用內核流,不僅可以避免大量的計算,還避免了內核數據與主機內存之間的拷貝過程。在這種情況下,用戶模式的Filter Graph中,即使pin之間是連接的,也不會有實際的數據流動。典型的情況,如帶有Video Port Pin的視頻捕捉卡,Preview時顯示的圖像就是在內核模式下直接傳送到顯卡的顯存的。所以,你也休想在VP Pin后面截獲數據流。

  講到這里,我想大家應該對DirectShow對硬件的支持問題有了一個總體的認識。對于應用程序開發人員來說,這方面的內容不用研究得太透,而只需作為背景知識了解一下就好了。其實,大量繁瑣的工作DirectShow已經幫我們做好了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/455405.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/455405.shtml
英文地址,請注明出處:http://en.pswp.cn/news/455405.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android selector中的item的順序

在selector中,要將默認狀態的item放在最后面,因為一旦前面的item滿足匹配條件,后面的item就不會去匹配。因此,把默認狀態的item放在前面的話,后面的item沒有執行的機會轉載于:https://www.cnblogs.com/xiaoyuersdch/p/…

權限表使用聯合主鍵嗎_天天寫 order by,你知道Mysql底層執行流程嗎?

前言 在實際的開發中一定會碰到根據某個字段進行排序后來顯示結果的需求,但是你真的理解order by在 Mysql 底層是如何執行的嗎?假設你要查詢城市是蘇州的所有人名字,并且按照姓名進行排序返回前 1000 個人的姓名、年齡,這條 sql 語…

nodejs簡介

nodejs是啥? Node.js是運行在服務端的JavaScript。 Node.js是一個基于Chrome JavaScript運行時建立的一個平臺。 Node.js是一個事件驅動I/O服務端JavaScript環境,基于Google的V8引擎,V8引擎執行Javascript的速度非常快,性能非常…

jumpserver v0.4.0 基于 CenOS7 的安裝詳解

標簽(linux): jumpserver 筆者Q:972581034 交流群:605799367。有任何疑問可與筆者或加群交流 首首先使用Jumpserver前要理解清楚這三個用戶關系: 1.用戶: 是指你在web上創建的用戶,會在跳板機上創建這個用戶,作用就是用…

Node.js中事件的循環

Node.js 事件循環 Node.js 是單進程單線程應用程序,但是通過事件和回調支持并發,所以性能非常高。 Node.js 的每一個 API 都是異步的,并作為一個獨立線程運行,使用異步函數調用,并處理并發。 Node.js 基本上所有的事…

python爬boss網站_python之requests爬蟲Boss數據

python之requests爬蟲Boss數據需要用到的庫:reqeusts、lxml沒有的可以用直接下載pip install requestspip install lxm這里以python崗位,地點北京為例爬取的數據就是崗位名稱、薪資、地點 首先導入需要用到的模塊import requestsfrom lxml import etree崗…

live555源代碼簡介

文章出自:http://blog.csdn.net/imliujie/archive/2008/01/30/2072657.aspx live555源代碼簡介liveMedia項目的源代碼包括四個基本的庫,各種測試代碼以及IVE555 Media Server。四個基本的庫分別是UsageEnvironment&TaskScheduler,groups…

并發無鎖隊列學習(單生產者單消費者模型)

1、引言 本文介紹單生產者單消費者模型的隊列。依據寫入隊列的內容是定長還是變長,分為單生產者單消費者定長隊列和單生產者單消費者變長隊列兩種。單生產者單消費者模型的隊列操作過程是不須要進行加鎖的。生產者通過寫索引控制入隊操作,消費者通過讀索…

ecshop 收貨人信息電話必填改為手機必填

首先通過在flow.dwt中,查找flow.php?stepconsignee中的關鍵字 consignee(結算中心)查找所在模板/Library/consignee.lbi 大概57行 把必填去掉,其次 在js/shopping_flow.js里邊注釋掉 if (Utils.isEmpty(frm.elements[‘tel’].v…

流媒體傳輸協議

1.流媒體( Streaming Media) 1.1流媒體概念 流媒體技術是網絡技術和多媒體技術發展到一定階段的產物。術語流媒體既可以指在網上傳輸連續時基媒體的流式技術,也可以指使用流式技術的連續時基媒體本身。在網上傳輸音頻、視頻等多媒體信息目前主要有兩種方式:下載和流…

關閉瀏覽器網頁觸發事件_淺析瀏覽器渲染和 script 加載

前言前端代碼離不開瀏覽器環境,理解 js、css 代碼如何在瀏覽器中工作是非常重要的。如何優化渲染過程中的回流,重繪?script 腳本在頁面中是怎么個加載順序?了解這些對前端性能優化起著非常大的作用。借著這篇文章,讓自…

Open vSwitch實驗常用命令

1. 基本架構 ovs-vsctl: 管理ovsdb-server的配置,提供OVSDB的配置方法,包括創建和刪除網橋、端口等; ovs-ofctl: 提供ovs-vswitchd的流表配置方法; ovs-dpctl: 配置OVS內核模塊,提供緩存流表的操作方法&#xff1b…

記IOS8中碰到的一個JS bug

IOS8的JS版本過低導致 var id "123"; var temp1 {id, "left": "200"}; // error in IOS8 var temp2 {"id":id, "left": "200"};平時還是多寫ES5的代碼,es6的語法總能碰到兼容的坑。 改了好幾天。…

Emmet的html語法

Emmet的html語法 所有操作按下“tab”鍵即可瞬間完成 元素 1.在編輯器中輸入元素名稱,即可自動補全生成 HTML 標簽,即使不是標準的 HTML 標簽。 2.輸入:! 或者 html:5 或者 html:4s 或者 html:4t 將自動補全html基本結構 嵌套操作 1.使用…

RTP Payload Format for H.264 Video

H.264 RTP協議的封裝格式rfc3984 英文原版:http://tools.ietf.org/html/rfc3984 部分中文翻譯: H.264 視頻 RTP 負載格式 1. 網絡抽象層單元類型 (NALU) NAL單元1字節包頭負載 NALU 頭由一個字節組成, 它的語法如下: —————|0|1|2|3|4|5|6|7|------…

js字符串、數組和數字常用方法總結

https://github.com/AnHyun/blog/issues/3 一、string 常用方法: 1.substring(start開始位置的索引,end結束位置索引) 截取的位置不包含結束位置的字符,只寫一個參數表示從開始位置截取到最后,輸入負值時將負值變為0,哪個較小作為開始位置 va…

Oracle 存儲過程錯誤之PLS-00201: 必須聲明標識符

轉自:http://blog.csdn.net/u010678947/article/details/20702149 錯誤: ORA-06550: 第 1 行, 第 7 列: PLS-00201: 必須聲明標識符ZUO.PROCE_TESTORA-06550: 第 1 行, 第 7 列: PL/SQL: Statement ignored 解決方法: (1&#x…

mysql中如何把兩個查詢結果列數不同并成一張表_MySQL

引言本文整理了MySQL相關的知識,方便以后查閱。 基礎架構下圖是 MySQL 的一個簡要架構圖,從下圖你可以很清晰的看到用戶的 SQL 語句在 MySQL 內部是如何執行的。 先簡單介紹一下下圖涉及的一些組件的基本作用幫助大家理解這幅圖。 - 連接器: …

JavaWeb筆記01-XML

今日內容 XML 概念語法解析 XML: 概念: Extensible Markup Language 可擴展標記語言 可擴展:標簽都是自定義的.<user><student> 功能 存儲數據 配置文件在網絡中傳輸 一個故事 由于瀏覽器之間的競爭,導致HTML發展的十分不順利 用戶:唉,這怎么報錯了呢?…

centos下如何使用sendmail發送郵件

最近在實施服務端日志監控腳本&#xff0c;需要對異常情況發送郵件通知相關責任人&#xff0c;記錄下centos通過sendmail發送郵件的配置過程。一. 安裝sendmail和mailx1、安裝sendmail&#xff1a;1): centos下可以安裝命令:yum install -y sendmail service sendmail start yu…