📄 ty.c
字号:
/* register the video stream */ es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( 'm', 'p', 'g', 'v' ) ); fmt.i_group = TY_ES_GROUP; p_sys->p_video = es_out_Add( p_demux->out, &fmt ); /* */ for( i = 0; i < 4; i++ ) p_sys->p_cc[i] = NULL; cc_Init( &p_sys->cc ); XdsInit( &p_sys->xds ); return VLC_SUCCESS;}/* =========================================================================== *//* Demux: Read & Demux one record from the chunk * * Returns -1 in case of error, 0 in case of EOF, 1 otherwise * * NOTE: I think we can return the number of packets sent instead of just 1. * that means we can demux an entire chunk and shoot it back (may be more efficient) * -- should try that some day :) -- */static int Demux( demux_t *p_demux ){ demux_sys_t *p_sys = p_demux->p_sys; ty_rec_hdr_t *p_rec; block_t *p_block_in = NULL; /*msg_Dbg(p_demux, "ty demux processing" );*/ /* did we hit EOF earlier? */ if( p_sys->eof ) return 0; /* * what we do (1 record now.. maybe more later): * - use stream_Read() to read the chunk header & record headers * - discard entire chunk if it is a PART header chunk * - parse all the headers into record header array * - keep a pointer of which record we're on * - use stream_Block() to fetch each record * - parse out PTS from PES headers * - set PTS for data packets * - pass the data on to the proper codec via es_out_Send() * if this is the first time or * if we're at the end of this chunk, start a new one */ /* parse the next chunk's record headers */ if( p_sys->b_first_chunk || p_sys->i_cur_rec >= p_sys->i_num_recs ) { if( get_chunk_header(p_demux) == 0 ) return 0; } /*====================================================================== * parse & send one record of the chunk *====================================================================== */ p_rec = &p_sys->rec_hdrs[p_sys->i_cur_rec]; if( !p_rec->b_ext ) { const long l_rec_size = p_rec->l_rec_size; /*msg_Dbg(p_demux, "Record Type 0x%x/%02x %ld bytes", subrec_type, p_rec->rec_type, l_rec_size );*/ /* some normal records are 0 length, so check for that... */ if( l_rec_size <= 0 ) { /* no data in payload; we're done */ p_sys->i_cur_rec++; return 1; } /* read in this record's payload */ if( !( p_block_in = stream_Block( p_demux->s, l_rec_size ) ) ) return 0; /* set these as 'unknown' for now */ p_block_in->i_pts = p_block_in->i_dts = 0; } /*else { -- don't read any data from the stream, data was in the record header -- msg_Dbg(p_demux, "Record Type 0x%02x/%02x, ext data = %02x, %02x", subrec_type, p_rec->rec_type, p_rec->ex1, p_rec->ex2); }*/ if( p_rec->rec_type == 0xe0 ) { /* Video */ DemuxRecVideo( p_demux, p_rec, p_block_in ); } else if ( p_rec->rec_type == 0xc0 ) { /* Audio */ DemuxRecAudio( p_demux, p_rec, p_block_in ); } else if( p_rec->rec_type == 0x01 || p_rec->rec_type == 0x02 ) { /* Closed Captions/XDS */ DemuxRecCc( p_demux, p_rec, p_block_in ); } else if ( p_rec->rec_type == 0x03 ) { /* Tivo data services (e.g. "thumbs-up to record!") useless for us */ if( p_block_in ) block_Release(p_block_in); } else if ( p_rec->rec_type == 0x05 ) { /* Unknown, but seen regularly */ if( p_block_in ) block_Release(p_block_in); } else { msg_Dbg(p_demux, "Invalid record type 0x%02x", p_rec->rec_type ); if( p_block_in ) block_Release(p_block_in); } /* */ p_sys->i_cur_rec++; return 1;}/* Control */static int Control(demux_t *p_demux, int i_query, va_list args){ demux_sys_t *p_sys = p_demux->p_sys; double f, *pf; int64_t i64, *p_i64; /*msg_Info(p_demux, "control cmd %d", i_query);*/ switch( i_query ) { case DEMUX_GET_POSITION: /* arg is 0.0 - 1.0 percent of overall file position */ if( ( i64 = p_sys->i_stream_size ) > 0 ) { pf = (double*) va_arg( args, double* ); *pf = (double)stream_Tell( p_demux->s ) / (double) i64; return VLC_SUCCESS; } return VLC_EGENERIC; case DEMUX_SET_POSITION: /* arg is 0.0 - 1.0 percent of overall file position */ f = (double) va_arg( args, double ); /* msg_Dbg(p_demux, "Control - set position to %2.3f", f); */ if ((i64 = p_sys->i_stream_size) > 0) return ty_stream_seek_pct(p_demux, f); return VLC_EGENERIC; case DEMUX_GET_TIME: /* return TiVo timestamp */ p_i64 = (int64_t *) va_arg(args, int64_t *); //*p_i64 = p_sys->lastAudioPTS - p_sys->firstAudioPTS; //*p_i64 = (p_sys->l_last_ty_pts / 1000) + (p_sys->lastAudioPTS - // p_sys->l_last_ty_pts_sync); *p_i64 = (p_sys->l_last_ty_pts / 1000); return VLC_SUCCESS; case DEMUX_GET_LENGTH: /* length of program in microseconds, 0 if unk */ /* size / bitrate */ p_i64 = (int64_t *) va_arg(args, int64_t *); *p_i64 = 0; return VLC_SUCCESS; case DEMUX_SET_TIME: /* arg is time in microsecs */ i64 = (int64_t) va_arg( args, int64_t ); return ty_stream_seek_time(p_demux, i64 * 1000); case DEMUX_GET_FPS: default: return VLC_EGENERIC; }}/* 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; XdsExit( &p_sys->xds ); cc_Exit( &p_sys->cc ); free( p_sys->rec_hdrs ); free( p_sys->seq_table ); free(p_sys);}/* =========================================================================== *//* Compute Presentation Time Stamp (PTS) * Assume buf points to beginning of PTS */static mtime_t get_pts( const uint8_t *buf ){ mtime_t i_pts; i_pts = ((mtime_t)(buf[0]&0x0e ) << 29)| (mtime_t)(buf[1] << 22)| ((mtime_t)(buf[2]&0xfe) << 14)| (mtime_t)(buf[3] << 7)| (mtime_t)(buf[4] >> 1); i_pts *= 100 / 9; /* convert PTS (90Khz clock) to microseconds */ return i_pts;}/* =========================================================================== */static int find_es_header( const uint8_t *header, const uint8_t *buffer, int i_search_len ){ int count; for( count = 0; count < i_search_len; count++ ) { if( !memcmp( &buffer[count], header, 4 ) ) return count; } return -1;}/* =========================================================================== *//* check if we have a full PES header, if not, then save what we have. * this is called when audio-start packets are encountered. * Returns: * 1 partial PES hdr found, some audio data found (buffer adjusted), * -1 partial PES hdr found, no audio data found * 0 otherwise (complete PES found, pts extracted, pts set, buffer adjusted) *//* TODO: HD support -- nothing known about those streams */static int check_sync_pes( demux_t *p_demux, block_t *p_block, int32_t offset, int32_t rec_len ){ demux_sys_t *p_sys = p_demux->p_sys; if ( offset < 0 || offset + p_sys->i_Pes_Length > rec_len ) { /* entire PES header not present */ msg_Dbg( p_demux, "PES header at %d not complete in record. storing.", offset ); /* save the partial pes header */ if( offset < 0 ) { /* no header found, fake some 00's (this works, believe me) */ memset( p_sys->pes_buffer, 4, 0 ); p_sys->i_pes_buf_cnt = 4; if( rec_len > 4 ) msg_Err( p_demux, "PES header not found in record of %d bytes!", rec_len ); return -1; } /* copy the partial pes header we found */ memcpy( p_sys->pes_buffer, p_block->p_buffer + offset, rec_len - offset ); p_sys->i_pes_buf_cnt = rec_len - offset; if( offset > 0 ) { /* PES Header was found, but not complete, so trim the end of this record */ p_block->i_buffer -= rec_len - offset; return 1; } return -1; /* partial PES, no audio data */ } /* full PES header present, extract PTS */ p_sys->lastAudioPTS = get_pts( &p_block->p_buffer[ offset + p_sys->i_Pts_Offset ] ); if (p_sys->firstAudioPTS < 0) p_sys->firstAudioPTS = p_sys->lastAudioPTS; p_block->i_pts = p_sys->lastAudioPTS; /*msg_Dbg(p_demux, "Audio PTS %lld", p_sys->lastAudioPTS );*/ /* adjust audio record to remove PES header */ memmove(p_block->p_buffer + offset, p_block->p_buffer + offset + p_sys->i_Pes_Length, rec_len - p_sys->i_Pes_Length); p_block->i_buffer -= p_sys->i_Pes_Length;#if 0 msg_Dbg(p_demux, "pes hdr removed; buffer len=%d and has " "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x", p_block->i_buffer, p_block->p_buffer[0], p_block->p_buffer[1], p_block->p_buffer[2], p_block->p_buffer[3], p_block->p_buffer[4], p_block->p_buffer[5], p_block->p_buffer[6], p_block->p_buffer[7], p_block->p_buffer[8], p_block->p_buffer[9], p_block->p_buffer[10], p_block->p_buffer[11], p_block->p_buffer[12], p_block->p_buffer[13], p_block->p_buffer[14], p_block->p_buffer[15]);#endif return 0;}static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_block_in ){ demux_sys_t *p_sys = p_demux->p_sys; const int subrec_type = rec_hdr->subrec_type; const long l_rec_size = rec_hdr->l_rec_size; // p_block_in->i_buffer might be better int esOffset1; int i; assert( rec_hdr->rec_type == 0xe0 ); if( !p_block_in ) return -1;#if 0 msg_Dbg(p_demux, "packet buffer has " "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x", p_block_in->p_buffer[0], p_block_in->p_buffer[1], p_block_in->p_buffer[2], p_block_in->p_buffer[3], p_block_in->p_buffer[4], p_block_in->p_buffer[5], p_block_in->p_buffer[6], p_block_in->p_buffer[7], p_block_in->p_buffer[8], p_block_in->p_buffer[9], p_block_in->p_buffer[10], p_block_in->p_buffer[11], p_block_in->p_buffer[12], p_block_in->p_buffer[13], p_block_in->p_buffer[14], p_block_in->p_buffer[15]);#endif //if( subrec_type == 0x06 || subrec_type == 0x07 ) if( subrec_type != 0x02 && subrec_type != 0x0c && subrec_type != 0x08 && l_rec_size > 4 ) { /* get the PTS from this packet if it has one. * on S1, only 0x06 has PES. On S2, however, most all do. * Do NOT Pass the PES Header to the MPEG2 codec */ esOffset1 = find_es_header( ty_VideoPacket, p_block_in->p_buffer, 5 ); if( esOffset1 != -1 ) { //msg_Dbg(p_demux, "Video PES hdr in pkt type 0x%02x at offset %d", //subrec_type, esOffset1); p_sys->lastVideoPTS = get_pts( &p_block_in->p_buffer[ esOffset1 + VIDEO_PTS_OFFSET ] ); /*msg_Dbg(p_demux, "Video rec %d PTS %"PRId64, p_sys->i_cur_rec, p_sys->lastVideoPTS );*/ if (subrec_type != 0x06) { /* if we found a PES, and it's not type 6, then we're S2 */ /* The packet will have video data (& other headers) so we * chop out the PES header and send the rest */ if (l_rec_size >= VIDEO_PES_LENGTH) { p_block_in->p_buffer += VIDEO_PES_LENGTH + esOffset1; p_block_in->i_buffer -= VIDEO_PES_LENGTH + esOffset1; } else { msg_Dbg(p_demux, "video rec type 0x%02x has short PES" " (%ld bytes)", subrec_type, l_rec_size); /* nuke this block; it's too short, but has PES marker */ p_block_in->i_buffer = 0; } } }/* else msg_Dbg(p_demux, "No Video PES hdr in pkt type 0x%02x", subrec_type); */ } if(subrec_type == 0x06 ) { /* type 6 (S1 DTivo) has no data, so we're done */ block_Release(p_block_in); return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -