📄 input_psi.c
字号:
/***************************************************************************** * psi.c: PSI management * Manages structures containing PSI information, and affiliated decoders. * TODO: Fonctions d'init des structures ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN * * Authors: * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include "defs.h"#include <sys/types.h> /* on BSD, uio.h needs types.h */#include <sys/uio.h> /* "input.h" */#include <stdlib.h> /* free(), realloc() */#include <string.h> /* bzero() */#include <netinet/in.h> /* ntohs() */#include "config.h"#include "common.h"#include "threads.h"#include "mtime.h"#include "intf_msg.h"#include "debug.h"#include "input.h"#include "input_ctrl.h"#include "input_psi.h"#include "main.h"/* * Precalculated 32-bits CRC table, shared by all instances of the PSI decoder */boolean_t b_crc_initialised = 0;u32 i_crc_32_table[256];/* * Global configuration variable, need by AUTO_SPAWN to determine * the option (audio and video) passed to the VideoLAN client. */#ifdef AUTO_SPAWN//XXX?? extern program_data_t *p_main;#endif/* * Locale type definitions */#define PSI_VIDEO_STREAM_DESCRIPTOR 0x02#define PSI_AUDIO_STREAM_DESCRIPTOR 0x03#define PSI_TARGET_BACKGROUND_GRID_DESCRIPTOR 0x07#define PSI_VIDEO_WINDOW_DESCRIPTOR 0x08#ifdef DVB_EXTENSIONS#define PSI_SERVICE_DESCRIPTOR 0x48#endif/* That info must be stored in the version field since it contains unused bits */#define PSI_UNINITIALISED 0xFF/* * Local prototypes */static int input_AddPsiPID( input_thread_t *p_input, int i_pid );static int input_DelPsiPID( input_thread_t *p_input, int i_pid );static void DecodePgrmAssocSection( byte_t* p_pas, input_thread_t *p_input );static void DecodePgrmMapSection( byte_t* p_pms, input_thread_t *p_input );static void DecodeSrvDescrSection( byte_t* p_sdt, input_thread_t *p_input );static void DecodePgrmDescriptor( byte_t* p_descr, pgrm_descriptor_t* p_pgrm );static void DecodeESDescriptor( byte_t* p_descriptor, es_descriptor_t* p_es );static stream_descriptor_t* AddStreamDescr( input_thread_t* p_input, u16 i_stream_id );static void DestroyStreamDescr( input_thread_t* p_input, u16 i_stream_id );static pgrm_descriptor_t* AddPgrmDescr( stream_descriptor_t* p_stream, u16 i_pgrm_id );static void DestroyPgrmDescr( input_thread_t* p_input, stream_descriptor_t* p_stream, u16 i_pgrm_id );static es_descriptor_t* AddESDescr( input_thread_t* p_input, pgrm_descriptor_t* p_pgrm, u16 i_es_pid );static void DestroyESDescr( input_thread_t* p_input, pgrm_descriptor_t* p_pgrm, u16 i_es_pid);static void BuildCrc32Table();static int CheckCRC32( u8* p_pms, int i_size);static boolean_t Is_known( byte_t* a_known_section, u8 i_section );static void Set_known( byte_t* a_known_section, u8 i_section );static void Unset_known( byte_t* a_known_section, u8 i_section );/***************************************************************************** * input_PsiInit: Initialize PSI decoder ***************************************************************************** * Init the structures in which the PSI decoder will put the informations it * got from PSI tables and request for the reception of the PAT. *****************************************************************************/int input_PsiInit( input_thread_t *p_input ){ ASSERT(p_input); /* Precalculate the 32-bit CRC table if not already done ? FIXME: Put a lock or do that at pgrm init ?? */ if( !b_crc_initialised ) { BuildCrc32Table(); b_crc_initialised = 1; } /* Init the structure that describes the stream we are receiving */ AddStreamDescr( p_input, PSI_UNINITIALISED ); /* Request for reception of the program association table */ input_AddPsiPID( p_input, 0 );#ifdef DVB_EXTENSIONS /* Request for reception of the service description table */ input_AddPsiPID( p_input, 17 );#endif return( 0 );}/***************************************************************************** * input_PsiClean: Clean PSI structures before dying *****************************************************************************/int input_PsiEnd( input_thread_t *p_input ){ ASSERT(p_input); /* Stop to receive all the PSI tables associated with that program */ /* FIXME: Not really useful ??*/ /* Clean also descriptors for programs associated with that stream */ /* FIXME: -> Not really useful and maybe buggy ??*/ /* Destroy the stream description */ DestroyStreamDescr( p_input, p_input->p_stream->i_stream_id ); return( 0 );}/***************************************************************************** * input_PsiRead: Read the table of programs ***************************************************************************** * Ugly debugging function at that time ? XXX?? *****************************************************************************/void input_PsiRead( input_thread_t *p_input /* XXX?? */ ){ int i_index; int i_index2; pgrm_descriptor_t* p_pgrm; ASSERT( p_input ); /* Lock the tables, since this method can be called from any thread */ //vlc_mutex_lock() /* Check if the table is complete or not */ if( !p_input->p_stream->b_is_PMT_complete ) { intf_IntfMsg( "Warning: PMT not yet complete\n" ); } /* Read the table */ for( i_index = 0; i_index < p_input->p_stream->i_pgrm_number; i_index++ ) { p_pgrm = p_input->p_stream->ap_programs[i_index]; intf_DbgMsg("Printing info for program %d\n", p_pgrm->i_number ); intf_IntfMsg("Printing info for program %d\n", p_pgrm->i_number ); for( i_index2 = 0; i_index2 < p_pgrm->i_es_number; i_index2++ ) { intf_DbgMsg( " ->Pid %d: type %d, PCR: %d, PSI: %d\n", p_pgrm->ap_es[i_index2]->i_id, p_pgrm->ap_es[i_index2]->i_type, p_pgrm->ap_es[i_index2]->b_pcr, p_pgrm->ap_es[i_index2]->b_psi); intf_IntfMsg( " ->Pid %d: type %d, PCR: %d, PSI: %d\n", p_pgrm->ap_es[i_index2]->i_id, p_pgrm->ap_es[i_index2]->i_type, p_pgrm->ap_es[i_index2]->b_pcr, p_pgrm->ap_es[i_index2]->b_psi); } } /* Unock the tables */ //vlc_mutex_unlock()}/***************************************************************************** * input_PsiDecode: Decode a PSI section ***************************************************************************** * This funtion is essentially a wrapper that will perform basic checks on * the section and then call the right function according to its type. *****************************************************************************/void input_PsiDecode( input_thread_t *p_input, psi_section_t* p_psi_section ){ ASSERT(p_input); ASSERT(p_psi_section); /* Hexa dump of the beginning of the section (for real men) */ //intf_DbgMsg( "Section: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", (u8)p_psi_section->buffer[0], (u8)p_psi_section->buffer[1], (u8)p_psi_section->buffer[2], (u8)p_psi_section->buffer[3], (u8)p_psi_section->buffer[4], (u8)p_psi_section->buffer[5], (u8)p_psi_section->buffer[6], (u8)p_psi_section->buffer[7], (u8)p_psi_section->buffer[8], (u8)p_psi_section->buffer[9], (u8)p_psi_section->buffer[10], (u8)p_psi_section->buffer[11], (u8)p_psi_section->buffer[12], (u8)p_psi_section->buffer[13], (u8)p_psi_section->buffer[14], (u8)p_psi_section->buffer[15], (u8)p_psi_section->buffer[16], (u8)p_psi_section->buffer[17], (u8)p_psi_section->buffer[18], (u8)p_psi_section->buffer[19] ); /* Check the CRC validity if any CRC is carried */#if 0 if( p_psi_section->buffer[1] & 0x80 ) { if( CheckCRC32 (p_psi_section->buffer, p_psi_section->i_length) ) { intf_DbgMsg("iSize: %d, CRC: %d\n", p_psi_section->i_length, U32_AT(&p_psi_section->buffer[p_psi_section->i_length-4])); intf_DbgMsg( "Invalid CRC for PSI\n" ); return; } }#endif /* If the section is not immediatly applicable, trash it (DVB drafts disallow transmission of such sections, so we didn't implement it) */ if( !p_psi_section->buffer[5] & 0x01 ) { intf_DbgMsg( "PSI not yet applicable: trash it\n" ); return; } /* Handle the packet according to it's type given it the table_id */ switch ( p_psi_section->buffer[0] ) { case 0x00: //intf_DbgMsg("Program association section received\n"); DecodePgrmAssocSection(p_psi_section->buffer, p_input); break; case 0x01: //intf_DbgMsg("Conditional access section received\n"); break; case 0x02: //intf_DbgMsg("Program map section received\n"); DecodePgrmMapSection(p_psi_section->buffer, p_input); break; case 0x42: //intf_DbgMsg("Service description section received\n"); DecodeSrvDescrSection(p_psi_section->buffer, p_input); break; default: //intf_DbgMsg("Private PSI data received (type %x), ignoring it\n", // p_psi_section->buffer[0]); }}/***************************************************************************** * DecodeAssocSection: Decode a PAS ***************************************************************************** * No check is made to known if the table is currently applicable or not, so * that unapplicable sections must be filtered before calling this function * The Program Association Table can be segmented to occupy multiple sections * so that we have to know which sections we have already received (IsKnown() / * SetKnown() calls) *****************************************************************************/static void DecodePgrmAssocSection(u8* p_pas, input_thread_t *p_input ){ u8 i_stream_id; /* Id of the stream described in that section */ u8 i_version; /* Version of the table carried in the section */ u16 i_pgrm_id; /* Id of the current described pgrm */ u16 i_pgrm_map_pid; /* PID of the associated program map table */ int i_pgrm_number; /* Number of programs described in the section */ boolean_t b_is_invalid = 0; u8 i_current_section; u8 i_last_section; int i_pgrm_index; int i_es_index; ASSERT(p_pas); ASSERT(p_input);#define p_descr (p_input->p_stream) /* Read stream id and version number immediately, to be sure they will be initialised in all cases we will need it */ i_stream_id = U16_AT(&p_pas[3]); i_version = (p_pas[5] >> 1) & 0x1F; //intf_DbgMsg("TS Id: %d, version: %d\n", U16_AT(&p_pas[3]),(p_pas[5] >> 1) & 0x1F); /* Test if the stream has not changed by looking at the stream_id */ if( p_descr->i_stream_id != i_stream_id ) { /* This can either mean that the PSI decoder has just started or that the stream has changed */ if( p_descr->i_PAT_version== PSI_UNINITIALISED ) intf_DbgMsg("Building Program Association table\n"); else intf_ErrMsg( "Stream Id has suddenly changed ! Rebuilding PAT\n" ); /* Whatever it is, ask the PSI decoder to rebuild the table */ b_is_invalid = 1; } else { /* Stream has not changed, test if the PMT is up to date */ if( p_descr->i_PAT_version != i_version ) { intf_DbgMsg("PAT has been updated, rebuilding it\n"); /* Ask the PSI decoder to rebuild the table */ b_is_invalid = 1; } } /* Clear the table if needed */ if( b_is_invalid ) { intf_DbgMsg("Updating PAT table\n"); /* Any program in the stream may have disapeared, or a new one can have been added. The good way to handle such a case would be to build a temporary table and to make a diff */ /* Stop the reception of all programs and PSI informations associated with this stream, excepted the PAT on PID 0 and the SDT on PID 17 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -