📄 ogg.c
字号:
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; int64_t *pi64; int i; switch( i_query ) { case DEMUX_GET_TIME: pi64 = (int64_t*)va_arg( args, int64_t * ); *pi64 = p_sys->i_pcr; return VLC_SUCCESS; case DEMUX_SET_TIME: return VLC_EGENERIC; case DEMUX_SET_POSITION: for( i = 0; i < p_sys->i_streams; i++ ) { logical_stream_t *p_stream = p_sys->pp_stream[i]; /* we'll trash all the data until we find the next pcr */ p_stream->b_reinit = 1; p_stream->i_pcr = -1; p_stream->i_interpolated_pcr = -1; ogg_stream_reset( &p_stream->os ); } ogg_sync_reset( &p_sys->oy ); default: return demux2_vaControlHelper( p_demux->s, 0, -1, p_sys->i_bitrate, 1, i_query, args ); }}/**************************************************************************** * Ogg_ReadPage: Read a full Ogg page from the physical bitstream. **************************************************************************** * Returns VLC_SUCCESS if a page has been read. An error might happen if we * are at the end of stream. ****************************************************************************/static int Ogg_ReadPage( demux_t *p_demux, ogg_page *p_oggpage ){ demux_sys_t *p_ogg = p_demux->p_sys ; int i_read = 0; byte_t *p_buffer; while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 ) { p_buffer = ogg_sync_buffer( &p_ogg->oy, OGG_BLOCK_SIZE ); i_read = stream_Read( p_demux->s, p_buffer, OGG_BLOCK_SIZE ); if( i_read <= 0 ) return VLC_EGENERIC; ogg_sync_wrote( &p_ogg->oy, i_read ); } return VLC_SUCCESS;}/**************************************************************************** * Ogg_UpdatePCR: update the PCR (90kHz program clock reference) for the * current stream. ****************************************************************************/static void Ogg_UpdatePCR( logical_stream_t *p_stream, ogg_packet *p_oggpacket ){ /* Convert the granulepos into a pcr */ if( p_oggpacket->granulepos >= 0 ) { if( p_stream->fmt.i_codec != VLC_FOURCC( 't','h','e','o' ) ) { p_stream->i_pcr = p_oggpacket->granulepos * I64C(1000000) / p_stream->f_rate; } else { ogg_int64_t iframe = p_oggpacket->granulepos >> p_stream->i_theora_keyframe_granule_shift; ogg_int64_t pframe = p_oggpacket->granulepos - ( iframe << p_stream->i_theora_keyframe_granule_shift ); p_stream->i_pcr = ( iframe + pframe ) * I64C(1000000) / p_stream->f_rate; } p_stream->i_interpolated_pcr = p_stream->i_pcr; } else { p_stream->i_pcr = -1; /* no granulepos available, try to interpolate the pcr. * If we can't then don't touch the old value. */ if( p_stream->fmt.i_cat == VIDEO_ES ) /* 1 frame per packet */ p_stream->i_interpolated_pcr += (I64C(1000000) / p_stream->f_rate); else if( p_stream->fmt.i_bitrate ) p_stream->i_interpolated_pcr += ( p_oggpacket->bytes * I64C(1000000) / p_stream->fmt.i_bitrate / 8 ); }}/**************************************************************************** * Ogg_DecodePacket: Decode an Ogg packet. ****************************************************************************/static void Ogg_DecodePacket( demux_t *p_demux, logical_stream_t *p_stream, ogg_packet *p_oggpacket ){ block_t *p_block; vlc_bool_t b_selected; int i_header_len = 0; mtime_t i_pts = -1, i_interpolated_pts; /* Sanity check */ if( !p_oggpacket->bytes ) { msg_Dbg( p_demux, "discarding 0 sized packet" ); return; } if( p_oggpacket->bytes >= 7 && ! strncmp ( &p_oggpacket->packet[0], "Annodex", 7 ) ) { /* it's an Annodex packet -- skip it (do nothing) */ return; } else if( p_oggpacket->bytes >= 7 && ! strncmp ( &p_oggpacket->packet[0], "AnxData", 7 ) ) { /* it's an AnxData packet -- skip it (do nothing) */ return; } /* Check the ES is selected */ es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, p_stream->p_es, &b_selected ); if( p_stream->b_force_backup ) { uint8_t *p_extra; vlc_bool_t b_store_size = VLC_TRUE; p_stream->i_packets_backup++; switch( p_stream->fmt.i_codec ) { case VLC_FOURCC( 'v','o','r','b' ): case VLC_FOURCC( 's','p','x',' ' ): case VLC_FOURCC( 't','h','e','o' ): if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0; break; case VLC_FOURCC( 'f','l','a','c' ): if( !p_stream->fmt.audio.i_rate && p_stream->i_packets_backup == 2 ) { Ogg_ReadFlacHeader( p_demux, p_stream, p_oggpacket ); p_stream->b_force_backup = 0; } else if( p_stream->fmt.audio.i_rate ) { p_stream->b_force_backup = 0; p_oggpacket->packet += 9; p_oggpacket->bytes -= 9; } b_store_size = VLC_FALSE; break; default: p_stream->b_force_backup = 0; break; } /* Backup the ogg packet (likely an header packet) */ p_stream->p_headers = realloc( p_stream->p_headers, p_stream->i_headers + p_oggpacket->bytes + (b_store_size ? 2 : 0) ); p_extra = p_stream->p_headers + p_stream->i_headers; if( b_store_size ) { *(p_extra++) = p_oggpacket->bytes >> 8; *(p_extra++) = p_oggpacket->bytes & 0xFF; } memcpy( p_extra, p_oggpacket->packet, p_oggpacket->bytes ); p_stream->i_headers += p_oggpacket->bytes + (b_store_size ? 2 : 0); if( !p_stream->b_force_backup ) { /* Last header received, commit changes */ p_stream->fmt.i_extra = p_stream->i_headers; p_stream->fmt.p_extra = realloc( p_stream->fmt.p_extra, p_stream->i_headers ); memcpy( p_stream->fmt.p_extra, p_stream->p_headers, p_stream->i_headers ); es_out_Control( p_demux->out, ES_OUT_SET_FMT, p_stream->p_es, &p_stream->fmt ); } b_selected = VLC_FALSE; /* Discard the header packet */ } /* Convert the pcr into a pts */ if( p_stream->fmt.i_codec == VLC_FOURCC( 'v','o','r','b' ) || p_stream->fmt.i_codec == VLC_FOURCC( 's','p','x',' ' ) || p_stream->fmt.i_codec == VLC_FOURCC( 'f','l','a','c' ) ) { if( p_stream->i_pcr >= 0 ) { /* This is for streams where the granulepos of the header packets * doesn't match these of the data packets (eg. ogg web radios). */ if( p_stream->i_previous_pcr == 0 && p_stream->i_pcr > 3 * DEFAULT_PTS_DELAY ) { es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); /* Call the pace control */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_stream->i_pcr ); } p_stream->i_previous_pcr = p_stream->i_pcr; /* The granulepos is the end date of the sample */ i_pts = p_stream->i_pcr; } } /* Convert the granulepos into the next pcr */ i_interpolated_pts = p_stream->i_interpolated_pcr; Ogg_UpdatePCR( p_stream, p_oggpacket ); if( p_stream->i_pcr >= 0 ) { /* This is for streams where the granulepos of the header packets * doesn't match these of the data packets (eg. ogg web radios). */ if( p_stream->i_previous_pcr == 0 && p_stream->i_pcr > 3 * DEFAULT_PTS_DELAY ) { es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); /* Call the pace control */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_stream->i_pcr ); } } if( p_stream->fmt.i_codec != VLC_FOURCC( 'v','o','r','b' ) && p_stream->fmt.i_codec != VLC_FOURCC( 's','p','x',' ' ) && p_stream->fmt.i_codec != VLC_FOURCC( 'f','l','a','c' ) && p_stream->i_pcr >= 0 ) { p_stream->i_previous_pcr = p_stream->i_pcr; /* The granulepos is the start date of the sample */ i_pts = p_stream->i_pcr; } if( !b_selected ) { /* This stream isn't currently selected so we don't need to decode it, * but we did need to store its pcr as it might be selected later on */ return; } if( !( p_block = block_New( p_demux, p_oggpacket->bytes ) ) ) return; /* Normalize PTS */ if( i_pts == 0 ) i_pts = 1; else if( i_pts == -1 && i_interpolated_pts == 0 ) i_pts = 1; else if( i_pts == -1 ) i_pts = 0; if( p_stream->fmt.i_cat == AUDIO_ES ) p_block->i_dts = p_block->i_pts = i_pts; else if( p_stream->fmt.i_cat == SPU_ES ) { p_block->i_dts = p_block->i_pts = i_pts; p_block->i_length = 0; } else if( p_stream->fmt.i_codec == VLC_FOURCC( 't','h','e','o' ) ) p_block->i_dts = p_block->i_pts = i_pts; else { p_block->i_dts = i_pts; p_block->i_pts = 0; } if( p_stream->fmt.i_codec != VLC_FOURCC( 'v','o','r','b' ) && p_stream->fmt.i_codec != VLC_FOURCC( 's','p','x',' ' ) && p_stream->fmt.i_codec != VLC_FOURCC( 'f','l','a','c' ) && p_stream->fmt.i_codec != VLC_FOURCC( 't','a','r','k' ) && p_stream->fmt.i_codec != VLC_FOURCC( 't','h','e','o' ) && p_stream->fmt.i_codec != VLC_FOURCC( 'c','m','m','l' ) ) { /* We remove the header from the packet */ i_header_len = (*p_oggpacket->packet & PACKET_LEN_BITS01) >> 6; i_header_len |= (*p_oggpacket->packet & PACKET_LEN_BITS2) << 1; if( p_stream->fmt.i_codec == VLC_FOURCC( 's','u','b','t' )) { /* But with subtitles we need to retrieve the duration first */ int i, lenbytes = 0; if( i_header_len > 0 && p_oggpacket->bytes >= i_header_len + 1 ) { for( i = 0, lenbytes = 0; i < i_header_len; i++ ) { lenbytes = lenbytes << 8; lenbytes += *(p_oggpacket->packet + i_header_len - i); } } if( p_oggpacket->bytes - 1 - i_header_len > 2 || ( p_oggpacket->packet[i_header_len + 1] != ' ' && p_oggpacket->packet[i_header_len + 1] != 0 && p_oggpacket->packet[i_header_len + 1] != '\n' && p_oggpacket->packet[i_header_len + 1] != '\r' ) ) { p_block->i_length = (mtime_t)lenbytes * 1000; } } i_header_len++; p_block->i_buffer -= i_header_len; } if( p_stream->fmt.i_codec == VLC_FOURCC( 't','a','r','k' ) ) { /* FIXME: the biggest hack I've ever done */ msg_Warn( p_demux, "tarkin pts: "I64Fd", granule: "I64Fd, p_block->i_pts, p_block->i_dts ); msleep(10000); } memcpy( p_block->p_buffer, p_oggpacket->packet + i_header_len, p_oggpacket->bytes - i_header_len ); es_out_Send( p_demux->out, p_stream->p_es, p_block );}/**************************************************************************** * Ogg_FindLogicalStreams: Find the logical streams embedded in the physical * stream and fill p_ogg. ***************************************************************************** * The initial page of a logical stream is marked as a 'bos' page. * Furthermore, the Ogg specification mandates that grouped bitstreams begin * together and all of the initial pages must appear before any data pages.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -