📄 ts.c
字号:
*****************************************************************************/static int Open( vlc_object_t *p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; const uint8_t *p_peek; int i_sync, i_peek, i; int i_packet_size; ts_pid_t *pat; const char *psz_mode; bool b_append; bool b_topfield = false; vlc_value_t val; if( stream_Peek( p_demux->s, &p_peek, TS_PACKET_SIZE_MAX ) < TS_PACKET_SIZE_MAX ) return VLC_EGENERIC; if( memcmp( p_peek, "TFrc", 4 ) == 0 ) { b_topfield = true; msg_Dbg( p_demux, "this is a topfield file" ); } /* Search first sync byte */ for( i_sync = 0; i_sync < TS_PACKET_SIZE_MAX; i_sync++ ) { if( p_peek[i_sync] == 0x47 ) break; } if( i_sync >= TS_PACKET_SIZE_MAX && !b_topfield ) { if( !p_demux->b_force ) return VLC_EGENERIC; msg_Warn( p_demux, "this does not look like a TS stream, continuing" ); } if( b_topfield ) { /* Read the entire Topfield header */ i_peek = TS_TOPFIELD_HEADER; } else { /* Check next 3 sync bytes */ i_peek = TS_PACKET_SIZE_MAX * 3 + i_sync + 1; } if( ( stream_Peek( p_demux->s, &p_peek, i_peek ) ) < i_peek ) { msg_Err( p_demux, "cannot peek" ); return VLC_EGENERIC; } if( p_peek[i_sync + TS_PACKET_SIZE_188] == 0x47 && p_peek[i_sync + 2 * TS_PACKET_SIZE_188] == 0x47 && p_peek[i_sync + 3 * TS_PACKET_SIZE_188] == 0x47 ) { i_packet_size = TS_PACKET_SIZE_188; } else if( p_peek[i_sync + TS_PACKET_SIZE_192] == 0x47 && p_peek[i_sync + 2 * TS_PACKET_SIZE_192] == 0x47 && p_peek[i_sync + 3 * TS_PACKET_SIZE_192] == 0x47 ) { i_packet_size = TS_PACKET_SIZE_192; } else if( p_peek[i_sync + TS_PACKET_SIZE_204] == 0x47 && p_peek[i_sync + 2 * TS_PACKET_SIZE_204] == 0x47 && p_peek[i_sync + 3 * TS_PACKET_SIZE_204] == 0x47 ) { i_packet_size = TS_PACKET_SIZE_204; } else if( p_demux->b_force ) { i_packet_size = TS_PACKET_SIZE_188; } else if( b_topfield ) { i_packet_size = TS_PACKET_SIZE_188;#if 0 /* I used the TF5000PVR 2004 Firmware .doc header documentation, * http://www.i-topfield.com/data/product/firmware/Structure%20of%20Recorded%20File%20in%20TF5000PVR%20(Feb%2021%202004).doc * but after the filename the offsets seem to be incorrect. - DJ */ int i_duration, i_name; char *psz_name = malloc(25); char *psz_event_name; char *psz_event_text = malloc(130); char *psz_ext_text = malloc(1025); // 2 bytes version Uimsbf (4,5) // 2 bytes reserved (6,7) // 2 bytes duration in minutes Uimsbf (8,9( i_duration = (int) (p_peek[8] << 8) | p_peek[9]; msg_Dbg( p_demux, "Topfield recording length: +/- %d minutes", i_duration); // 2 bytes service number in channel list (10, 11) // 2 bytes service type Bslbf 0=TV 1=Radio Bslb (12, 13) // 4 bytes of reserved + tuner info (14,15,16,17) // 2 bytes of Service ID Bslbf (18,19) // 2 bytes of PMT PID Uimsbf (20,21) // 2 bytes of PCR PID Uimsbf (22,23) // 2 bytes of Video PID Uimsbf (24,25) // 2 bytes of Audio PID Uimsbf (26,27) // 24 bytes filename Bslbf memcpy( psz_name, &p_peek[28], 24 ); psz_name[24] = '\0'; msg_Dbg( p_demux, "recordingname=%s", psz_name ); // 1 byte of sat index Uimsbf (52) // 3 bytes (1 bit of polarity Bslbf +23 bits reserved) // 4 bytes of freq. Uimsbf (56,57,58,59) // 2 bytes of symbol rate Uimsbf (60,61) // 2 bytes of TS stream ID Uimsbf (62,63) // 4 bytes reserved // 2 bytes reserved // 2 bytes duration Uimsbf (70,71) //i_duration = (int) (p_peek[70] << 8) | p_peek[71]; //msg_Dbg( p_demux, "Topfield 2nd duration field: +/- %d minutes", i_duration); // 4 bytes EventID Uimsbf (72-75) // 8 bytes of Start and End time info (76-83) // 1 byte reserved (84) // 1 byte event name length Uimsbf (89) i_name = (int)(p_peek[89]&~0x81); msg_Dbg( p_demux, "event name length = %d", i_name); psz_event_name = malloc( i_name+1 ); // 1 byte parental rating (90) // 129 bytes of event text memcpy( psz_event_name, &p_peek[91], i_name ); psz_event_name[i_name] = '\0'; memcpy( psz_event_text, &p_peek[91+i_name], 129-i_name ); psz_event_text[129-i_name] = '\0'; msg_Dbg( p_demux, "event name=%s", psz_event_name ); msg_Dbg( p_demux, "event text=%s", psz_event_text ); // 12 bytes reserved (220) // 6 bytes reserved // 2 bytes Event Text Length Uimsbf // 4 bytes EventID Uimsbf // FIXME We just have 613 bytes. not enough for this entire text // 1024 bytes Extended Event Text Bslbf memcpy( psz_ext_text, p_peek+372, 1024 ); psz_ext_text[1024] = '\0'; msg_Dbg( p_demux, "extended event text=%s", psz_ext_text ); // 52 bytes reserved Bslbf#endif } else { msg_Warn( p_demux, "TS module discarded (lost sync)" ); return VLC_EGENERIC; } p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; memset( p_sys, 0, sizeof( demux_sys_t ) ); p_sys->i_packet_size = i_packet_size; vlc_mutex_init( &p_sys->csa_lock ); /* Fill dump mode fields */ p_sys->i_write = 0; p_sys->p_file = NULL; p_sys->b_file_out = false; p_sys->psz_file = var_CreateGetString( p_demux, "ts-dump-file" ); if( *p_sys->psz_file != '\0' ) { p_sys->b_file_out = true; var_Create( p_demux, "ts-dump-append", VLC_VAR_BOOL|VLC_VAR_DOINHERIT ); var_Get( p_demux, "ts-dump-append", &val ); b_append = val.b_bool; if ( b_append ) psz_mode = "ab"; else psz_mode = "wb"; if( !strcmp( p_sys->psz_file, "-" ) ) { msg_Info( p_demux, "dumping raw stream to standard output" ); p_sys->p_file = stdout; } else if( ( p_sys->p_file = utf8_fopen( p_sys->psz_file, psz_mode ) ) == NULL ) { msg_Err( p_demux, "cannot create `%s' for writing", p_sys->psz_file ); p_sys->b_file_out = false; } if( p_sys->b_file_out ) { vlc_value_t bufsize; /* Determine how many packets to read. */ var_Create( p_demux, "ts-dump-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_demux, "ts-dump-size", &bufsize ); p_sys->i_ts_read = (int) (bufsize.i_int / p_sys->i_packet_size); if( p_sys->i_ts_read <= 0 ) { p_sys->i_ts_read = 1500 / p_sys->i_packet_size; } p_sys->buffer = malloc( p_sys->i_packet_size * p_sys->i_ts_read ); msg_Info( p_demux, "%s raw stream to file `%s' reading packets %d", b_append ? "appending" : "dumping", p_sys->psz_file, p_sys->i_ts_read ); } } /* Fill p_demux field */ if( p_sys->b_file_out ) p_demux->pf_demux = DemuxFile; else p_demux->pf_demux = Demux; p_demux->pf_control = Control; /* Init p_sys field */ p_sys->b_meta = true; p_sys->b_dvb_control = true; p_sys->i_dvb_program = 0; p_sys->i_dvb_start = 0; p_sys->i_dvb_length = 0; for( i = 0; i < 8192; i++ ) { ts_pid_t *pid = &p_sys->pid[i]; pid->i_pid = i; pid->b_seen = false; pid->b_valid = false; } /* PID 8191 is padding */ p_sys->pid[8191].b_seen = true; p_sys->i_packet_size = i_packet_size; p_sys->b_udp_out = false; p_sys->i_ts_read = 50; p_sys->csa = NULL; /* Init PAT handler */ pat = &p_sys->pid[0]; PIDInit( pat, true, NULL ); pat->psi->handle = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_demux );#ifdef TS_USE_DVB_SI if( p_sys->b_meta ) { ts_pid_t *sdt = &p_sys->pid[0x11]; ts_pid_t *eit = &p_sys->pid[0x12]; PIDInit( sdt, true, NULL ); sdt->psi->handle = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_demux ); PIDInit( eit, true, NULL ); eit->psi->handle = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_demux ); if( p_sys->b_dvb_control ) { if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_SET_PRIVATE_ID_STATE, 0x11, true ) || stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_SET_PRIVATE_ID_STATE, 0x12, true ) ) p_sys->b_dvb_control = false; } }#endif /* Init PMT array */ p_sys->i_pmt = 0; p_sys->pmt = NULL; /* Read config */ var_Create( p_demux, "ts-es-id-pid", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_demux, "ts-es-id-pid", &val ); p_sys->b_es_id_pid = val.b_bool; var_Create( p_demux, "ts-out", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_demux, "ts-out", &val ); if( val.psz_string && *val.psz_string && !p_sys->b_file_out ) { vlc_value_t mtu; char *psz = strchr( val.psz_string, ':' ); int i_port = 0; p_sys->b_udp_out = true; if( psz ) { *psz++ = '\0'; i_port = atoi( psz ); } if( i_port <= 0 ) i_port = 1234; msg_Dbg( p_demux, "resend ts to '%s:%d'", val.psz_string, i_port ); p_sys->fd = net_ConnectUDP( VLC_OBJECT(p_demux), val.psz_string, i_port, 0 ); if( p_sys->fd < 0 ) { msg_Err( p_demux, "failed to open udp socket, send disabled" ); p_sys->b_udp_out = false; } else { var_Create( p_demux, "ts-out-mtu", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_demux, "ts-out-mtu", &mtu ); p_sys->i_ts_read = mtu.i_int / p_sys->i_packet_size; if( p_sys->i_ts_read <= 0 ) { p_sys->i_ts_read = 1500 / p_sys->i_packet_size; } p_sys->buffer = malloc( p_sys->i_packet_size * p_sys->i_ts_read ); } } free( val.psz_string ); /* We handle description of an extra PMT */ var_Create( p_demux, "ts-extra-pmt", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_demux, "ts-extra-pmt", &val ); p_sys->b_user_pmt = false; if( val.psz_string && *val.psz_string ) UserPmt( p_demux, val.psz_string ); free( val.psz_string ); var_Create( p_demux, "ts-csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND ); var_Get( p_demux, "ts-csa-ck", &val ); if( val.psz_string && *val.psz_string ) { int i_res; vlc_value_t csa2; p_sys->csa = csa_New(); var_Create( p_demux, "ts-csa2-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND); var_Get( p_demux, "ts-csa2-ck", &csa2 ); i_res = csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, true ); if( i_res == VLC_SUCCESS && csa2.psz_string && *csa2.psz_string ) { if( csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, csa2.psz_string, false ) != VLC_SUCCESS ) { csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, false ); } } else if ( i_res == VLC_SUCCESS ) { csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, false ); } else { csa_Delete( p_sys->csa ); p_sys->csa = NULL; } if( p_sys->csa ) { vlc_value_t pkt_val; var_AddCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, (void *)1 ); var_AddCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL ); var_Create( p_demux, "ts-csa-pkt", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_demux, "ts-csa-pkt", &pkt_val ); if( pkt_val.i_int < 4 || pkt_val.i_int > 188 ) { msg_Err( p_demux, "wrong packet size %d specified.", pkt_val.i_int ); msg_Warn( p_demux, "using default packet size of 188 bytes" ); p_sys->i_csa_pkt_size = 188; } else p_sys->i_csa_pkt_size = pkt_val.i_int; msg_Dbg( p_demux, "decrypting %d bytes of packet", p_sys->i_csa_pkt_size ); } free( csa2.psz_string ); } free( val.psz_string ); var_Create( p_demux, "ts-silent", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_demux, "ts-silent", &val ); p_sys->b_silent = val.b_bool; return VLC_SUCCESS;}/***************************************************************************** * Close *****************************************************************************/static void Close( vlc_object_t *p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = p_demux->p_sys; int i; msg_Dbg( p_demux, "pid list:" ); for( i = 0; i < 8192; i++ ) { ts_pid_t *pid = &p_sys->pid[i]; if( pid->b_valid && pid->psi ) { switch( pid->i_pid ) { case 0: /* PAT */ dvbpsi_DetachPAT( pid->psi->handle ); free( pid->psi ); break; case 1: /* CAT */ free( pid->psi ); break; case 0x11: /* SDT */ case 0x12: /* EIT */ dvbpsi_DetachDemux( pid->psi->handle ); free( pid->psi ); break; default: PIDClean( p_demux->out, pid ); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -