Files
2026-08-24 10:03:24 +08:00

538 lines
17 KiB
C

#ifndef CA_DEBUG_LEVEL
#define CA_DEBUG_LEVEL 2
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
//#include <time.h>
#include <sys/time.h>
#include "AmTsPlayer.h"
#include "am_dmx.h"
#include "am_cas.h"
#include "scan.h"
#define DMX_DEV_NO (0)
static int parse_pat_section( const uint8_t *data, int sec_len, void *user_data );
static int parse_pmt_section( const uint8_t *data, void *user_data );
static int parse_cat_section( const uint8_t *data, void *user_data );
static void section_callback( int dev_no, int fid, const uint8_t *data, int len, void *user_data );
static int parse_ca_descriptor( uint8_t *p, dvb_service_info_t **dvb_info, uint16_t len, int index, int type );
static dvb_service_info_t g_info[16];
int pat_done_flag = 0;
int pmt_done_flag = 0;
int cat_done_flag = 0;
int g_pmt_num = 0;
uint32_t g_start_time = 0;
int file_read(const char *name, char *buf, int len)
{
FILE *fp;
int ret;
fp = fopen(name, "r");
if(!fp)
{
CA_DEBUG(1, "cannot open file \"%s\"", name);
return -1;
}
ret = fread(buf, 1, len, fp);
if(!ret)
{
CA_DEBUG(1, "read the file:\"%s\" error:\"%s\" failed", name, strerror(errno));
}
fclose(fp);
return ret ? 0 : -1;
}
static uint32_t time_ms(void)
{
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return tv.tv_sec * 1000 + tv.tv_nsec / 1000000;
}
static int parse_pat_section( const uint8_t *data, int sec_len, void *user_data )
{
dvb_service_info_t *p_dvb_info = (dvb_service_info_t *)user_data;
if (pat_done_flag) {
CA_DEBUG( 1, "%s, pat receive is done ,return", __FUNCTION__ );
return 0;
}
uint8_t pmt_num = 0, i = 0;
uint16_t program_num = 0;
uint8_t *p = NULL;
p = ( uint8_t * )( data + 8 );
pmt_num = ( sec_len - 12 ) / 4 + 1;
CA_DEBUG( 2, "data 8 Byte:%#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x",
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7] );
CA_DEBUG( 1, "%s, pmt_num:%d, sec_len:%d", __FUNCTION__, pmt_num, sec_len );
if ( p_dvb_info == NULL ) {
for ( i = 0; i < pmt_num; i++ ) {
CA_DEBUG( 1, "@data: %#x, %#x, %#x, %#x ", p[0], p[1], p[2], p[3] );
program_num = ( p[0] << 8 | p[1] );
if ( program_num != 0 ) {
g_pmt_num++;
CA_DEBUG( 1, "%s, 111, get program:%d, g_pmt_num:%d", __FUNCTION__, program_num, g_pmt_num );
}
p += 4;
}
pat_done_flag = 1;
return 0;
}
int j = 0;
for ( i = 0; i < pmt_num; i++ ) {
CA_DEBUG( 2, "data: %#x, %#x, %#x, %#x ", p[0], p[1], p[2], p[3] );
program_num = ( p[0] << 8 | p[1] );
if ( program_num != 0 ) {
p_dvb_info[j].i_program_num = program_num;
p_dvb_info[j].i_pmt_pid = ( ( p[2] << 8 | p[3] ) & 0x1FFF );
CA_DEBUG( 1, "%s, 222, get program:%d, pmt_pid:%#x", __FUNCTION__, p_dvb_info[j].i_program_num, p_dvb_info[j].i_pmt_pid );
g_pmt_num++;
j++;
}
p += 4;
}
pat_done_flag = 1;
return 0;
}
static int parse_pmt_section( const uint8_t *data, void *user_data )
{
dvb_service_info_t *p_dvb_info = ( dvb_service_info_t * )user_data;
if ( p_dvb_info == NULL ) {
return 0;
}
uint16_t program_num = 0, program_info_len = 0, ca_system_id = 0, ca_pid = 0, sec_len = 0;
uint8_t desc_tag = 0, desc_len = 0;
uint8_t *p = NULL;
int i = 0, index = 0, type = TYPE_INVALID;
p = ( uint8_t * )data;
sec_len = ( ( p[1] << 8 | p[2] ) & 0x0FFF );
program_num = ( p[3] << 8 | p[4] );
program_info_len = ( ( p[10] << 8 | p[11] ) & 0x0FFF );
for ( i = 0; i < g_pmt_num; i++ ) {
if ( p_dvb_info[i].i_program_num == program_num ) {
index = i;
break;
}
}
CA_DEBUG( 1, "%s, program_num:%d, program_info_len:%d, sec_len:%d",
__FUNCTION__, program_num, program_info_len, sec_len );
p += 12;
sec_len -= 9;
sec_len -= program_info_len;
while ( program_info_len ) {
CA_DEBUG( 2, "data: %#x, %#x, %#x, %#x, %#x, %#x ", p[0], p[1], p[2], p[3], p[4], p[5] );
desc_tag = p[0];
desc_len = p[1];
ca_system_id = p[2] << 8 | p[3];
ca_pid = ( ( p[4] << 8 | p[5] ) & 0x1FFF );
if (desc_tag == 0x9)
CA_DEBUG( 1, "%s, desc_tag:%d, desc_len:%d, ca_system_id:%#x, ca_pid:%#x",
__FUNCTION__, desc_tag, desc_len, ca_system_id, ca_pid );
if (desc_tag == 0x65) {
CA_DEBUG(1, "Scrambling_descriptor(0x65) is found, algo:%#x\n", p[2]);
p_dvb_info[index].private_data[0] = 3;
p_dvb_info[index].private_data[1] = 0;
p_dvb_info[index].private_data[2] = p[2];
}
if ( AM_CA_IsSystemIdSupported(ca_system_id) ) {
p_dvb_info[index].i_ca_system_id = ca_system_id;
p_dvb_info[index].i_ecm_pid[0] = p_dvb_info[index].i_ecm_pid[1] = ca_pid;
p_dvb_info[index].scrambled = 1;
}
if ( desc_len > 4 ) {
CA_DEBUG( 1, "%s, @@this is ca_private_data, data:%#x",
__FUNCTION__, p[6]);
p_dvb_info[index].private_data[0] = 3;
p_dvb_info[index].private_data[1] = 1;
p_dvb_info[index].private_data[2] = p[6];
}
program_info_len -= ( desc_len + 2 );
p += ( desc_len + 2 );
}
uint8_t stream_type;
uint16_t pid, es_info_len;
CA_DEBUG( 1, "decode es_info, sec_len:%d, data: %#x, %#x, %#x, %#x, %#x",
sec_len, p[0], p[1], p[2], p[3], p[4] );
while ( sec_len > 4 ) {
stream_type = p[0];
pid = ( ( p[1] << 8 | p[2] ) & 0x1FFF );
es_info_len = ( ( p[3] << 8 | p[4] ) & 0x0FFF );
sec_len -= ( 5 + es_info_len );
CA_DEBUG( 1, "es_info, stream_type:%d, pid:%#x, es_info_len:%d, sec_len:%d\n",
stream_type, pid, es_info_len, sec_len );
if (p_dvb_info[index].i_video_pid == 0 ||
p_dvb_info[index].i_audio_pid == 0) {
switch ( stream_type ) {
/*video pid and video format*/
case 0x1:
case 0x2:
CA_DEBUG( 1, "video pid:%#x, vformat is mpeg12", pid );
p_dvb_info[index].i_vformat = AV_VIDEO_CODEC_MPEG2;
p_dvb_info[index].i_video_pid = pid;
type = TYPE_VIDEO;
break;
case 0x10:
CA_DEBUG( 1, "video pid:%#x, vformat is mpeg4", pid );
p_dvb_info[index].i_vformat = AV_VIDEO_CODEC_AUTO;
p_dvb_info[index].i_video_pid = pid;
type = TYPE_VIDEO;
break;
case 0x1b:
CA_DEBUG( 1, "video pid:%#x, vformat is h264", pid );
p_dvb_info[index].i_vformat = AV_VIDEO_CODEC_H264;
p_dvb_info[index].i_video_pid = pid;
type = TYPE_VIDEO;
break;
case 0x24:
CA_DEBUG( 1, "video pid:%#x, vformat is hevc", pid );
p_dvb_info[index].i_vformat = AV_VIDEO_CODEC_H265;
p_dvb_info[index].i_video_pid = pid;
type = TYPE_VIDEO;
break;
case 0xea:
CA_DEBUG( 1, "video pid:%#x, vformat is vc1", pid );
p_dvb_info[index].i_vformat = AV_VIDEO_CODEC_AUTO;
p_dvb_info[index].i_video_pid = pid;
type = TYPE_VIDEO;
break;
case 0x42:
CA_DEBUG( 1, "video pid:%#x, vformat is avs", pid );
p_dvb_info[index].i_vformat = AV_VIDEO_CODEC_AUTO;
p_dvb_info[index].i_video_pid = pid;
type = TYPE_VIDEO;
break;
/*audio pid and audio format*/
case 0x3:
case 0x4:
CA_DEBUG( 1, "audio pid:%#x, aformat is mpeg", pid );
p_dvb_info[index].i_aformat = AV_AUDIO_CODEC_MP3;
p_dvb_info[index].i_audio_pid = pid;
type = TYPE_AUDIO;
break;
case 0x0f:
CA_DEBUG( 1, "audio pid:%#x, aformat is aac", pid );
p_dvb_info[index].i_aformat = AV_AUDIO_CODEC_AAC;
p_dvb_info[index].i_audio_pid = pid;
type = TYPE_AUDIO;
break;
case 0x11:
CA_DEBUG( 1, "audio pid:%#x, aformat is aac_latm", pid );
p_dvb_info[index].i_aformat = AV_AUDIO_CODEC_LATM;
p_dvb_info[index].i_audio_pid = pid;
type = TYPE_AUDIO;
break;
case 0x81:
CA_DEBUG( 1, "audio pid:%#x, aformat is ac3", pid );
p_dvb_info[index].i_aformat = AV_AUDIO_CODEC_AC3;
p_dvb_info[index].i_audio_pid = pid;
type = TYPE_AUDIO;
break;
case 0x8A:
case 0x82:
case 0x85:
case 0x86:
CA_DEBUG( 1, "audio pid:%#x, aformat is dts", pid );
p_dvb_info[index].i_aformat = AV_AUDIO_CODEC_DTS;
p_dvb_info[index].i_audio_pid = pid;
type = TYPE_AUDIO;
break;
case 0x6:
CA_DEBUG( 1, "!!! private pes desc, todo... !!!" );
break;
}
}
parse_ca_descriptor( p+5, &p_dvb_info, es_info_len, index, type );
p += ( 5 + es_info_len );
}
for ( i = 0; i < g_pmt_num; i++ ) {
if ( p_dvb_info[i].i_video_pid == 0 ) {
break;
}
}
if ( g_start_time == 0 ) {
g_start_time = time_ms();
}
if ( i >= g_pmt_num || time_ms() - g_start_time >= 5000 ) {
// read all pmt or took more than x seconds, consider it done
pmt_done_flag = 1;
}
return 0;
}
static int parse_cat_section( const uint8_t *data, void *user_data )
{
dvb_service_info_t *p_dvb_info = ( dvb_service_info_t * )user_data;
if ( p_dvb_info == NULL ) {
return 0;
}
uint16_t ca_system_id = 0, ca_pid = 0, sec_len = 0;
uint8_t desc_tag = 0, desc_len = 0;
uint8_t *p = NULL;
int i = 0, index = 0;
p = ( uint8_t * )data;
sec_len = ( ( p[1] << 8 | p[2] ) & 0x0FFF );
p += 8;
if ( sec_len <= 5 )
return 0;
sec_len -= 5;
while ( sec_len > 9 ) {
CA_DEBUG( 2, "%s, cat data: %#x, %#x, %#x, %#x, %#x, %#x ", __FUNCTION__,
p[0], p[1], p[2], p[3], p[4], p[5] );
desc_tag = p[0];
desc_len = p[1];
ca_system_id = ( ( p[2] << 8 ) | p[3] );
ca_pid = ( ( p[4] << 8 ) | p[5] ) & 0x1FFF;
if ( sec_len < ( desc_len + 2 ) )
break;
sec_len -= ( desc_len + 2 );
p += ( desc_len + 2 );
if ( AM_CA_IsSystemIdSupported(ca_system_id) ) {
p_dvb_info[index].i_ca_system_id = ca_system_id;
for ( i = 0; i < g_pmt_num; i++ ) {
p_dvb_info[i].i_ca_pid = ca_pid;
}
}
CA_DEBUG( 1, "%s, get cat, tag:%d, len:%d, ca_sys_id:%#x, ca_pid:%#x", __FUNCTION__, desc_tag, desc_len, ca_system_id, ca_pid );
}
cat_done_flag = 1;
return 0;
}
static int parse_ca_descriptor( uint8_t *p, dvb_service_info_t **dvb_info, uint16_t len, int index, int type )
{
uint16_t ca_system_id = 0, ca_pid = 0;
uint8_t desc_tag = 0, desc_len = 0;
dvb_service_info_t *p_dvb_info = *dvb_info;
while ( len ) {
CA_DEBUG( 2, "%s, data: %#x, %#x, %#x, %#x, %#x, %#x ", __FUNCTION__, p[0], p[1], p[2], p[3], p[4], p[5] );
desc_tag = p[0];
desc_len = p[1];
ca_system_id = p[2] << 8 | p[3];
ca_pid = ( ( p[4] << 8 | p[5] ) & 0x1FFF );
CA_DEBUG( 1, "%s, desc_tag:%#x, desc_len:%d, ca_system_id:%#x, ca_pid:%#x",
__FUNCTION__, desc_tag, desc_len, ca_system_id, ca_pid);
if( desc_tag != 0x9 ) {
CA_DEBUG(1, "%s, this tag is not ca descriptor", __FUNCTION__);
switch( desc_tag ) {
case 0x6A:
CA_DEBUG(1, "!!Found AC3 Descriptor!!!");
break;
case 0x7A:
CA_DEBUG(1, "!!Found Enhanced AC3 Descriptor!!!");
break;
case 0x7C:
CA_DEBUG(1, "!!Found AAC Descriptor!!!");
break;
case 0x7B:
CA_DEBUG(1, "!!Found DTS Descriptor!!!");
break;
case 0xA0:
CA_DEBUG(1, "!!Found DRA Descriptor!!!");
break;
}
} else {
CA_DEBUG(1, "%s, find a ca descriptor", __FUNCTION__);
if ( desc_len > 4 ) {
CA_DEBUG( 1, "%s, @@this is ca_private_data, data:%#x",
__FUNCTION__, p[6]);
p_dvb_info[index].private_data[0] = 3;
p_dvb_info[index].private_data[1] = 1;
p_dvb_info[index].private_data[2] = p[6];
}
if ( AM_CA_IsSystemIdSupported(ca_system_id) ) {
p_dvb_info[index].i_ca_system_id = ca_system_id;
if ( type == TYPE_AUDIO ) {
p_dvb_info[index].i_ecm_pid[0] = ca_pid;
} else if ( type == TYPE_VIDEO ){
p_dvb_info[index].i_ecm_pid[1] = ca_pid;
} else if ( type == TYPE_SUBTITLE ) {
p_dvb_info[index].i_ecm_pid[2] = ca_pid;
} else if ( type == TYPE_INVALID ) {
p_dvb_info[index].i_ecm_pid[0] = p_dvb_info[index].i_ecm_pid[1] = p_dvb_info[index].i_ecm_pid[2] = ca_pid;
}
}
}
len -= ( desc_len + 2 );
p += ( desc_len + 2 );
}
return 0;
}
static void section_callback(int dev_no, int fid, const uint8_t *data, int len, void *user_data)
{
uint8_t tid = 0;
uint16_t sec_len = 0;
UNUSED(dev_no);
UNUSED(fid);
UNUSED(len);
if (data == NULL) {
CA_DEBUG(0, "%s, param error", __FUNCTION__);
return;
}
tid = data[0];
sec_len = (((data[1] & 0x0f) << 4) | data[2]);
switch (tid) {
case 0: //PAT
CA_DEBUG(1,"%s, get a pat section\n", __FUNCTION__);
parse_pat_section( data, sec_len, user_data );
break;
case 2: //PMT
CA_DEBUG(1,"%s, get a pmt section\n", __FUNCTION__);
parse_pmt_section( data, user_data );
break;
case 1: //CAT
CA_DEBUG(1,"%s, get a cat section\n", __FUNCTION__);
parse_cat_section( data, user_data );
break;
default:
CA_DEBUG(1, "%s, unknown section\n", __FUNCTION__);
}
return;
}
int aml_scan(void)
{
int i;
int filter_handle = -1;
struct dmx_sct_filter_params filter_param;
memset(g_info, 0, sizeof(g_info));
am_dmx_init();
g_start_time = 0;
am_dmx_alloc_filter(DMX_DEV_NO, &filter_handle);
if (filter_handle < 0) {
CA_DEBUG(1,"alloc dmx pat filter handle FAILED! %d\n", filter_handle);
return 0;
}
CA_DEBUG(1,"alloc dmx pat filter handle = %d\n", filter_handle);
am_dmx_set_callback(DMX_DEV_NO, filter_handle, section_callback, g_info);
memset(&filter_param, 0, sizeof(filter_param));
filter_param.pid = 0;
filter_param.filter.filter[0] = 0;
filter_param.filter.mask[0] = 0xff;
filter_param.flags = 1;
am_dmx_set_sec_filter(DMX_DEV_NO, filter_handle, &filter_param );
am_dmx_set_buffer_size(DMX_DEV_NO, filter_handle, 32 * 1024);
am_dmx_start_filter( DMX_DEV_NO, filter_handle);
CA_DEBUG(1,"start PAT filter");
while (!pat_done_flag) {
usleep(100 * 1000);
}
CA_DEBUG(1,"@@ %s, pat is receive done. pmt_num: %d \n", __FUNCTION__, g_pmt_num);
am_dmx_stop_filter(DMX_DEV_NO, filter_handle);
am_dmx_free_filter(DMX_DEV_NO, filter_handle);
CA_DEBUG(1,"start PMT filter");
int pmt_filter_handles[g_pmt_num];
for (i = 0; i < g_pmt_num; i++) {
am_dmx_alloc_filter(DMX_DEV_NO, &pmt_filter_handles[i]);
am_dmx_set_callback(DMX_DEV_NO, pmt_filter_handles[i], section_callback, g_info);
memset(&filter_param, 0x0, sizeof(filter_param));
filter_param.pid = g_info[i].i_pmt_pid;
filter_param.filter.filter[0] = 2;
filter_param.filter.mask[0] = 0xff;
filter_param.flags = 1;
am_dmx_set_sec_filter(DMX_DEV_NO, pmt_filter_handles[i], &filter_param);
am_dmx_set_buffer_size(DMX_DEV_NO, pmt_filter_handles[i], 32 * 1024);
am_dmx_start_filter(DMX_DEV_NO, pmt_filter_handles[i]);
}
while (!pmt_done_flag) {
usleep(10*1000);
}
CA_DEBUG(1,"@@ %s, pmt is receive done.\n", __FUNCTION__);
for(i = 0; i < g_pmt_num; i++) {
am_dmx_stop_filter(DMX_DEV_NO, pmt_filter_handles[i]);
am_dmx_free_filter(DMX_DEV_NO, pmt_filter_handles[i]);
}
#if 1
am_dmx_alloc_filter(DMX_DEV_NO, &filter_handle);
am_dmx_set_callback(DMX_DEV_NO, filter_handle, section_callback, g_info);
memset(&filter_param, 0x0, sizeof(filter_param));
filter_param.pid = 1;
filter_param.filter.filter[0] = 1;
filter_param.filter.mask[0] = 0xff;
filter_param.flags = 1;
am_dmx_set_sec_filter(DMX_DEV_NO, filter_handle, &filter_param);
am_dmx_set_buffer_size(DMX_DEV_NO, filter_handle, 32 * 1024);
am_dmx_start_filter(DMX_DEV_NO, filter_handle);
while (!cat_done_flag) {
static int timeout = 0;
sleep(1);
if (++timeout >= 5) {
break;
}
}
CA_DEBUG(1,"@@ %s, cat is receive done.\n", __FUNCTION__);
am_dmx_stop_filter(DMX_DEV_NO, filter_handle);
am_dmx_free_filter(DMX_DEV_NO, filter_handle);
#endif
return g_pmt_num;
}
dvb_service_info_t* aml_get_program(uint32_t prog_index)
{
int i;
for (i = 0; i < g_pmt_num; i++) {
printf("program_num:%d vpid:%d, apid:%d\r\n",
g_info[i].i_program_num,
g_info[i].i_video_pid,
g_info[i].i_audio_pid);
if (prog_index == g_info[i].i_program_num) {
return &g_info[i];
}
}
printf("\r\n");
if (prog_index+1 > g_pmt_num) {
return &g_info[prog_index%g_pmt_num];
}
return &g_info[prog_index];
}