linux平臺的數字電視驅動被稱作linux DVB 驅動
其框架稱爲DVB core
在此做簡單介紹
Demux 簡介
編碼器爲每一路的基本業務的傳送包賦予一個唯一的包標誌符PID ,
同時將這些PID的賦值信息寫入到節目映射表(PMT)的控制信息表中。每一路節目一個PMT表,記錄的是該路節目的視頻流的PID,音頻流的PID。
各個PMT的PID統一記錄在PAT表中。PAT的PID 爲0。
TS流解析流程
TS流中查找PID爲0的TS包,即PAT表
根據表獲取不同頻道的PMT表所使用的PID
根據這些PID獲取不同頻道的PMT
根據PMT表獲取頻道中的音視頻PID
根據音視頻PID 獲取音視頻TS包
獲取到TS包之後,TS包->PES包->ES包->解碼器。
linux DVB 驅動設備文件模型
DTV 播放,使用demux0
PVR Record , 使用demux1 DVR1
PVR Play, 使用demux0, DVR0
demux節點
/dev/dvb/adapter0/demux0
/dev/dvb/adapter0/demux1
1, open: 可以多次打開。每次打開將會分配一個新的 filter handle。
2, read : 讀取sections,即PAT,PMT表
3,ioctl: DMX_SET_PES_FILTER
設置pes 過濾,即只讀取某pid的TS碼流。
設置TS流出口
typedef enum
{
DMX_OUT_DECODER,
DMX_OUT_TAP,
DMX_OUT_TS_TAP
} dmx_output_t;
DMX_OUT_DECODER:將流輸出到解碼器上
DMX_OUT_TAP:將流輸出到demux設備上
/dev/dvb/adapter0/demux0
DMX_OUT_TS_TAP:將流輸出到邏輯 DVR設備上 /dev/dvb/adapter0/dvr0
DVR 節點
dev/dvb/adapter0/dvr0
dev/dvb/adapter0/dvr1是一個邏輯設備。
從該設備讀取,將得到一個TS流。
該流就是在demux設備上設置了PES PID過濾、設置了DMX_OUT_TS_TAP標誌之後,從demux 過濾出來的TS。
index節點
dev/dvb/adapter0/dvr_idx1
dev/dvb/adapter0/dvr_idx0
用來讀寫index流。
typedef struct
{
driver_picture_type_e picture_type;
unsigned long long packet_count;
unsigned int timecode;
unsigned long long pts;
}pvr_index_rawdata_s;
Index是解碼器生成的,並非TS流中自帶原始數據。
每個單元長32字節,主要描述了某一幀數據的I\B\P類型,在TS流中的位置、PTS時間戳。
PVR錄製典型例程
1,鎖住tuner頻率 (另文討論,不做贅述)
2,打開dvr設備/index設備
dvb_dvr_open
dvb_dvr_idx_open
3,demux設置:
設置PES過濾所需PID,以及TS流輸出方向
4, 設置trustzone加解密
5,進入循環,從dvr讀,向目標文件寫
While()
{
Read dvr
Read index
Write file
}
採用如下代碼打開DVR設備結點
flags = O_RDONLY | O_NONBLOCK;
sprintf(filename, "/dev/dvb/adapter%i/dvr%i", adapter, dvr);
fd = open(filename, flags);
採用如下代碼打開index設備結點
int flags = O_RDONLY | O_NONBLOCK;
sprintf(filename, "/dev/dvb/adapter%i/dvr_idx%i", adapter, dvr_idx);
fd = open(filename, flags);
採用如下代碼設置index設備結點
dvr_index_config_t index_config;
index_config.video_format = DVR_VIDEO_FAMAT_MPEG; //根據視頻流的格式設置
index_config.interval = 0; //通常情況下設置0
ioctl(idxFd, DVR_IDX_SET_CONFIG, &index_config ) ;
採用如下代碼打開demux設備結點
asprintf(&demux_name, "/dev/dvb/adapter%i/demux%i", adapter, demux );
int fd_demux = open( demux_name, O_RDWR | O_NONBLOCK );
採用如下代碼設置demux設備結點
對於每個需要得到的pid, 下面代碼均需要調用一次。
有幾個pid就調用幾次,同時要將pesfilter.pes_type 字段設置成pid對應的類型。
例如一個電視節目有audio,video,pcr, 三個pid數據流,則下面代碼就應該被調用三次,同時
pesfilter.pes_type分別設置成DMX_PES_AUDIO3, DMX_PES_VIDEO3, DMX_PES_PCR3
struct dmx_pes_filter_params pesfilter;
pesfilter.pid = pid;
pesfilter.input = DMX_IN_FRONTEND; //表示數據來自於前段電纜信號線
pesfilter.output = DVB_DMX_OUT_DVR; //表示數據輸出到DVR設備
pesfilter.pes_type = DMX_PES_AUDIO3; //表示這一路pid數據是音頻數據
pesfilter.flags = DMX_IMMEDIATE_START; //常規設置,不需要改變
ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter)
經過前面幾步,初始化設置就完成了,數據就會上來,這裏就可以進行循環讀寫了
這裏一共要讀兩種數據,
1,TS流數據,這個就是音視頻文件的數據,直接存入文件系統即可。
2,index數據,此數據主要描述音視頻的幀類型和時間碼 ,經過二次封裝,形成GOP信息,存入文件系統即可。
While()
{
Read index data from index_dvr
Analysis index data, produce GOP information
Save the GOP information to GOP file
Read TS data from dvr
Write TS data to DVR
}
PVR播放典型例程
1,打開dvr設備
dev/dvb/adapter0/dvr0
dvb_dvr_open
2,demux設置:
dev/dvb/adapter0/demux0
設置PES過濾所需PID,以及TS流輸出方向
3,設置trustzone解密
4,進入循環,從文件讀,向DVR寫
While()
{
Read file
Write DVR
}
經過前面幾步,初始化設置就完成了,這裏就可以進行循環讀寫,將數據送入DVR
這裏一共要處理兩種數據,
1,讀GOP信息,從中得到音視頻幀的位置,時間碼等信息。
2,根據得到的音視頻幀位置,從TS文件中讀出音視頻幀,送入DVR。
While()
{
Read GOP file
Analysis GOP data,
Get the correct location of TS file
Read TS data from the correct location of TS file
Write TS data to DVR
}
PVR幾個特殊場景
1,節目具有多路音頻的場景
例如有兩路音頻,audio_1 ,audio_2
設置demux pid filter的時候,要如下設置:
設置audio_1 的 pesfilter.pes_type = DMX_PES_AUDIO3;
設置audio_2 的 pesfilter.pes_type = DMX_PES_OTHER;
如果還有更多路音頻,例如三路以上,只需要把多出來的音頻均設置成 DMX_PES_OTHER即可。
2,Audio_only場景
audio——only是隻錄製音頻,不錄製視頻的場景,
此時設置index設備結點屬性的時候,視頻格式做如下設置:
index_config.video_format = DVR_VIDEO_FAMAT_NONE;
DVB 核心代碼
Linux自身定義的DVB框架性代碼。
主要實現設備註冊,設備讀寫,回調函數,內存管理等框架性代碼
從linux框架的角度規定了對設備文件讀寫控制,不關心上層的具體業務,只處理設備文件相關操作。
Kernal/drivers/media/platform/sdp/sdp_demux
Dvb功能實現的具體代碼。與設備硬件強相關。
是dvb-core代碼中各種掛接函數的具體實現。
負責操作管理硬件。
響應dvb-core傳遞下來的各種上層業務,通過對硬件的操作實際完成各種具體操作。
Dvb-core 代碼介紹
Dvbdev.c
定義了DVB各設備的註冊函數。
便於實際初始化函數調用。
Dmxdev.c
定義了dvb中demux、dvr、index等設備文件的操作函數框架。
例如open、ioctl、read等函數的大致形式就定義在此。其中含多函數都採用了函數指針的形式,指向具體的函數實現。
Dvb_demux.c
對demux設備文件使用到的主要結構體進行初始化。對demux的feed、filter等功能定義了框架代碼。
Dvb_ringbuffer.c
定義了DVB-core所使用的環形內存讀寫管理方式
Demux 驅動運行流程
demux的數據輸出爲PVR寄存器
PVR硬件模塊解封裝TS流,輸出ES流到解碼器MFC
同時demux模塊還能將TS流用DMA方式輸出到到內存dvb_bufferring, 便於TS流讀操作,錄製TS 流
PVR還能接收dvb_bufferring用DMA方式送過來的數據流,解封TS流,輸出ES流到解碼器
dvb_bufferring的驅動運轉是靠中斷驅動的。
如果此時是在寫PVR,
PVR 模塊中的ES流輸出給解碼器後,PVR的中斷會告知現在PVR中有空間可用,DMA開始寫入
DMA完畢的中斷髮生後,觸發回調函數,從dvb_bufferring 裏面更新一下環,
同時通知用戶態現在有空間可以寫入了,
DMA的目的地址是PVR模塊地址,DMA源地址是更新完畢的dvb_bufferring裏面的數據區
如果此時是在讀PVR,
demux模塊中的TS包數量達到閾值後,產生中斷,開始DMA到dvb_bufferring
DMA完畢後,DMA中斷產生,從dvb_bufferring 裏面更新一下環,
DMA的目的地址是dvb_bufferring裏面的數據區,DMA源地址是demux寄存器
ES流buffer只有一塊,PVR往裏面DMA。
MFC解碼完後,有個PCR硬件模塊,接收TS流裏的時間同步信息。根據這個同步信息不斷對自己調整
MFC在DTV模式下,會告訴PCR模塊,這一幀的PTS和解碼完比的地址。
PCR對時間做一下調整,就會通知顯示模塊顯示
DTV解碼時,會告訴MFC現在是DTV模式,不是MM模式