[vlc-commits] demux: ogg: rework and simplify
Francois Cartegnie
git at videolan.org
Thu May 31 18:47:54 CEST 2018
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu May 24 18:40:26 2018 +0200| [bc9f6bb1ce26c07fded6b1065cff4ac194b68f28] | committer: Francois Cartegnie
demux: ogg: rework and simplify
Was no longer understandable mess
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=bc9f6bb1ce26c07fded6b1065cff4ac194b68f28
---
modules/demux/Makefile.am | 6 +-
modules/demux/ogg.c | 447 ++++++++++++++++++++++----------------------
modules/demux/ogg.h | 17 +-
modules/demux/ogg_granule.c | 187 ++++++++++++++++++
modules/demux/ogg_granule.h | 27 +++
modules/demux/oggseek.c | 149 ++-------------
modules/demux/oggseek.h | 14 +-
7 files changed, 467 insertions(+), 380 deletions(-)
diff --git a/modules/demux/Makefile.am b/modules/demux/Makefile.am
index 6f799e84c4..28e32f29d6 100644
--- a/modules/demux/Makefile.am
+++ b/modules/demux/Makefile.am
@@ -10,8 +10,10 @@ libflacsys_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
libflacsys_plugin_la_LIBADD = libxiph_metadata.la
demux_LTLIBRARIES += libflacsys_plugin.la
-libogg_plugin_la_SOURCES = demux/ogg.c demux/ogg.h demux/oggseek.c demux/oggseek.h \
- demux/xiph.h demux/opus.h
+libogg_plugin_la_SOURCES = demux/ogg.c demux/ogg.h \
+ demux/oggseek.c demux/oggseek.h \
+ demux/ogg_granule.c demux/ogg_granule.h \
+ demux/xiph.h demux/opus.h
libogg_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBVORBIS_CFLAGS) $(OGG_CFLAGS)
libogg_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(demuxdir)'
libogg_plugin_la_LIBADD = $(LIBVORBIS_LIBS) $(OGG_LIBS) libxiph_metadata.la
diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c
index eeaf09acaa..4d52b3e194 100644
--- a/modules/demux/ogg.c
+++ b/modules/demux/ogg.c
@@ -29,6 +29,10 @@
# include "config.h"
#endif
+#ifdef HAVE_LIBVORBIS
+ #include <vorbis/codec.h>
+#endif
+
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_access.h>
@@ -44,6 +48,7 @@
#include "xiph_metadata.h"
#include "ogg.h"
#include "oggseek.h"
+#include "ogg_granule.h"
#include "opus.h"
/*****************************************************************************
@@ -121,7 +126,6 @@ static int Control( demux_t *, int, va_list );
/* Bitstream manipulation */
static int Ogg_ReadPage ( demux_t *, ogg_page * );
-static void Ogg_UpdatePCR ( demux_t *, logical_stream_t *, ogg_packet * );
static void Ogg_DecodePacket ( demux_t *, logical_stream_t *, ogg_packet * );
static unsigned Ogg_OpusPacketDuration( ogg_packet * );
static void Ogg_SendOrQueueBlocks( demux_t *, logical_stream_t *, block_t * );
@@ -580,8 +584,11 @@ static int Demux( demux_t * p_demux )
if ( p_stream->prepcr.pp_blocks )
{
- mtime_t pagestamp = Oggseek_GranuleToAbsTimestamp( p_stream, ogg_page_granulepos( &p_sys->current_page ), false );
- p_stream->i_previous_pcr = pagestamp;
+ mtime_t i_end = Ogg_GranuleToTime( p_stream,
+ ogg_page_granulepos( &p_sys->current_page ),
+ false, false );
+ mtime_t i_end_backup = i_end;
+
#ifdef HAVE_LIBVORBIS
int i_prev_blocksize = 0;
#endif
@@ -624,9 +631,8 @@ static int Demux( demux_t * p_demux )
// PASS 2
bool b_fixed = false;
- date_t d;
- date_Init( &d, p_stream->f_rate, 1 );
- date_Set( &d, p_sys->i_nzpcr_offset + pagestamp - VLC_TS_0 );
+ date_t d = p_stream->dts;
+ date_Set( &d, p_sys->i_nzpcr_offset + i_end - VLC_TS_0 );
for( int i=p_stream->prepcr.i_used - 1; i>=0; i-- )
{
block_t *p_block = p_stream->prepcr.pp_blocks[i];
@@ -635,7 +641,7 @@ static int Demux( demux_t * p_demux )
case VLC_CODEC_SPEEX:
case VLC_CODEC_OPUS:
case VLC_CODEC_VORBIS:
- if( pagestamp != VLC_TS_INVALID )
+ if( i_end != VLC_TS_INVALID )
{
date_Decrement( &d, p_block->i_nb_samples );
p_block->i_pts = date_Get( &d ) + VLC_TS_0;
@@ -651,7 +657,7 @@ static int Demux( demux_t * p_demux )
default:
if ( p_stream->fmt.i_cat == VIDEO_ES )
{
- if( pagestamp != VLC_TS_INVALID )
+ if( i_end != VLC_TS_INVALID )
{
date_Decrement( &d, 1 );
p_block->i_pts = date_Get( &d ) + VLC_TS_0;
@@ -663,26 +669,22 @@ static int Demux( demux_t * p_demux )
if ( b_fixed )
{
- pagestamp = p_stream->i_previous_pcr; /* as set above */
- p_stream->i_pcr = pagestamp;
- p_stream->i_pcr += p_sys->i_nzpcr_offset;
- p_stream->i_previous_granulepos = ogg_page_granulepos( &p_sys->current_page );
+ i_end = i_end_backup; /* as set above */
+ if( i_end != VLC_TS_INVALID )
+ p_stream->i_pcr = i_end + p_sys->i_nzpcr_offset;
}
FREENULL(p_stream->prepcr.pp_blocks);
p_stream->prepcr.i_used = 0;
Ogg_SendOrQueueBlocks( p_demux, p_stream, NULL );
-
}
- mtime_t i_pagestamp = Oggseek_GranuleToAbsTimestamp( p_stream,
- ogg_page_granulepos( &p_sys->current_page ), false );
- if ( i_pagestamp != VLC_TS_INVALID )
- {
- p_stream->i_pcr = i_pagestamp;
- p_stream->i_pcr += p_sys->i_nzpcr_offset;
- }
+ mtime_t i_pcr = Ogg_GranuleToTime( p_stream,
+ ogg_page_granulepos( &p_sys->current_page ),
+ !p_stream->b_contiguous, false );
+ if ( i_pcr != VLC_TS_INVALID )
+ p_stream->i_pcr = p_sys->i_nzpcr_offset + i_pcr;
if( !p_sys->b_page_waiting )
break;
@@ -727,8 +729,7 @@ static void Ogg_ResetStream( logical_stream_t *p_stream )
/* we'll trash all the data until we find the next pcr */
p_stream->b_reinit = true;
p_stream->i_pcr = VLC_TS_UNKNOWN;
- p_stream->i_previous_granulepos = -1;
- p_stream->i_previous_pcr = VLC_TS_UNKNOWN;
+ date_Set( &p_stream->dts, VLC_TS_INVALID );
ogg_stream_reset( &p_stream->os );
FREENULL( p_stream->prepcr.pp_blocks );
p_stream->prepcr.i_size = 0;
@@ -1026,133 +1027,69 @@ static int Ogg_ReadPage( demux_t *p_demux, ogg_page *p_oggpage )
return VLC_SUCCESS;
}
-/****************************************************************************
- * Ogg_UpdatePCR: update the PCR (90kHz program clock reference) for the
- * current stream.
- ****************************************************************************/
-static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream,
- ogg_packet *p_oggpacket )
+static void Ogg_SetNextFrame( demux_t *p_demux, logical_stream_t *p_stream,
+ ogg_packet *p_oggpacket )
{
- demux_sys_t *p_ogg = p_demux->p_sys;
- p_stream->i_end_trim = 0;
+ VLC_UNUSED(p_demux);
+ ogg_int64_t i_granule = p_oggpacket->granulepos;
- /* Convert the granulepos into a pcr */
- if ( p_oggpacket->granulepos == 0 )
+ if( Ogg_GranuleIsValid( p_stream, i_granule ) )
{
- /* We're in headers, and we haven't parsed 1st data packet yet */
-// p_stream->i_pcr = VLC_TS_UNKNOWN;
- if( p_stream->b_oggds && p_oggpacket->bytes > 0 &&
- (p_oggpacket->packet[0] & PACKET_TYPE_HEADER) == 0 )
+ mtime_t i_endtime = Ogg_GranuleToTime( p_stream, i_granule, false, false );
+ assert( !p_stream->b_contiguous || i_endtime != VLC_TS_INVALID );
+ if( i_endtime != VLC_TS_INVALID )
{
- p_stream->i_pcr = VLC_TS_0 + p_ogg->i_nzpcr_offset;
+ date_Set( &p_stream->dts, i_endtime );
+ return;
}
}
- else if( p_oggpacket->granulepos > 0 )
+
+ /* Do Interpolation if can't compute directly from granule */
+ if( date_Get( &p_stream->dts ) != VLC_TS_INVALID )
{
- if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
- p_stream->fmt.i_codec == VLC_CODEC_DAALA ||
- p_stream->fmt.i_codec == VLC_CODEC_KATE ||
- p_stream->fmt.i_codec == VLC_CODEC_VP8 ||
- p_stream->fmt.i_codec == VLC_CODEC_DIRAC ||
- p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
- p_stream->fmt.i_codec == VLC_CODEC_OGGSPOTS ||
- (p_stream->b_oggds && p_stream->fmt.i_cat == VIDEO_ES) )
+ if( p_stream->fmt.i_cat == VIDEO_ES )
{
- p_stream->i_pcr = Oggseek_GranuleToAbsTimestamp( p_stream,
- p_oggpacket->granulepos, true );
- p_stream->i_pcr += p_ogg->i_nzpcr_offset;
+ date_Increment( &p_stream->dts, 1 );
}
- else if ( p_stream->i_previous_granulepos > 0 )
+ else if( p_stream->fmt.i_cat == AUDIO_ES )
{
- ogg_int64_t sample = p_stream->i_previous_granulepos;
-
- if( p_stream->fmt.i_codec == VLC_CODEC_OPUS && p_oggpacket->e_o_s )
- p_stream->i_end_trim = p_oggpacket->granulepos - sample;
-
- sample -= p_stream->i_pre_skip;
-
- p_stream->i_pcr = VLC_TS_0 + sample * CLOCK_FREQ / p_stream->f_rate;
- p_stream->i_pcr += p_ogg->i_nzpcr_offset;
- }
-
- }
- else if ( p_oggpacket->granulepos == -1 )
- {
- unsigned i_duration;
- /* no granulepos available, try to interpolate the pcr.
- * If we can't then don't touch the old value. */
- if( p_stream->b_oggds && p_stream->fmt.i_cat == VIDEO_ES )
- {
- if( p_stream->i_previous_granulepos > 0 )
- {
- p_stream->i_pcr = Oggseek_GranuleToAbsTimestamp( p_stream, ++p_stream->i_previous_granulepos, false );
- p_stream->i_pcr += p_ogg->i_nzpcr_offset;
- }
- /* First frame in ogm can be -1 (0 0 -1 2 3 -1 5 ...) */
- else if( p_stream->i_previous_granulepos == 0 )
- {
- p_stream->i_pcr = VLC_TS_0 + p_ogg->i_nzpcr_offset;
- }
- else
+ int64_t i_samples = 0;
+ switch( p_stream->fmt.i_codec )
{
- p_stream->i_pcr += (CLOCK_FREQ / p_stream->f_rate);
- }
- }
+ case VLC_CODEC_OPUS:
+ i_samples = Ogg_OpusPacketDuration( p_oggpacket );
+ break;
+ case VLC_CODEC_SPEEX:
+ i_samples = p_stream->special.speex.i_framesize *
+ p_stream->special.speex.i_framesperpacket;
+ break;
#ifdef HAVE_LIBVORBIS
- else if ( p_stream->fmt.i_codec == VLC_CODEC_VORBIS &&
- p_stream->special.vorbis.p_info &&
- VORBIS_HEADERS_VALID(p_stream) &&
- p_stream->i_previous_granulepos > 0 )
- {
- long i_blocksize = vorbis_packet_blocksize(
- p_stream->special.vorbis.p_info, p_oggpacket );
- if ( p_stream->special.vorbis.i_prev_blocksize )
- i_duration = ( i_blocksize + p_stream->special.vorbis.i_prev_blocksize ) / 4;
- else
- i_duration = i_blocksize / 2;
- p_stream->special.vorbis.i_prev_blocksize = i_blocksize;
- /* duration in samples per channel */
- p_oggpacket->granulepos = p_stream->i_previous_granulepos + i_duration;
- p_stream->i_pcr = p_stream->i_previous_granulepos *
- CLOCK_FREQ / p_stream->special.vorbis.p_info->rate;
- p_stream->i_pcr += p_ogg->i_nzpcr_offset;
- }
+ case VLC_CODEC_VORBIS:
+ if( p_stream->special.vorbis.p_info &&
+ VORBIS_HEADERS_VALID(p_stream) )
+ {
+ long i_blocksize = vorbis_packet_blocksize(
+ p_stream->special.vorbis.p_info, p_oggpacket );
+ /* duration in samples per channel */
+ if ( p_stream->special.vorbis.i_prev_blocksize )
+ i_samples = ( i_blocksize + p_stream->special.vorbis.i_prev_blocksize ) / 4;
+ else
+ i_samples = i_blocksize / 2;
+ p_stream->special.vorbis.i_prev_blocksize = i_blocksize;
+ }
+ break;
#endif
- else if ( p_stream->fmt.i_codec == VLC_CODEC_SPEEX &&
- p_stream->i_previous_granulepos > 0 )
- {
- i_duration = p_stream->special.speex.i_framesize *
- p_stream->special.speex.i_framesperpacket;
- p_oggpacket->granulepos = p_stream->i_previous_granulepos + i_duration;
- p_stream->i_pcr = Oggseek_GranuleToAbsTimestamp( p_stream,
- p_stream->i_previous_granulepos, false );
- p_stream->i_pcr += p_ogg->i_nzpcr_offset;
- }
- else if( p_stream->fmt.i_codec == VLC_CODEC_OPUS &&
- p_stream->i_previous_granulepos > 0 &&
- ( i_duration =
- Ogg_OpusPacketDuration( p_oggpacket ) ) > 0 )
- {
- ogg_int64_t sample;
- p_oggpacket->granulepos = p_stream->i_previous_granulepos + i_duration;
- sample = p_stream->i_previous_granulepos;
- sample -= p_stream->i_pre_skip;
-
- p_stream->i_pcr = VLC_TS_0 + sample * CLOCK_FREQ / p_stream->f_rate;
- p_stream->i_pcr += p_ogg->i_nzpcr_offset;
- }
- else if( p_stream->fmt.i_cat == VIDEO_ES && p_stream->i_pcr > VLC_TS_UNKNOWN )
- {
- p_stream->i_pcr += (CLOCK_FREQ / p_stream->f_rate);
- }
- else if( p_stream->fmt.i_bitrate && p_stream->i_pcr > VLC_TS_UNKNOWN )
- {
- p_stream->i_pcr += ( CLOCK_FREQ * p_oggpacket->bytes /
- p_stream->fmt.i_bitrate / 8 );
+ default:
+ if( p_stream->fmt.i_bitrate )
+ {
+ i_samples = 8 * p_oggpacket->bytes * p_stream->dts.i_divider_num;
+ i_samples /= p_stream->fmt.i_bitrate / p_stream->dts.i_divider_den;
+ }
+ break;
+ }
+ date_Increment( &p_stream->dts, i_samples );
}
}
-
- p_stream->i_previous_granulepos = p_oggpacket->granulepos;
}
static void Ogg_SendOrQueueBlocks( demux_t *p_demux, logical_stream_t *p_stream,
@@ -1223,6 +1160,17 @@ static void Ogg_SendOrQueueBlocks( demux_t *p_demux, logical_stream_t *p_stream,
}
}
+static bool Ogg_IsHeaderPacket( const logical_stream_t *p_stream,
+ const ogg_packet *p_oggpacket )
+{
+ if ( p_stream->b_oggds )
+ {
+ return p_oggpacket->bytes > 0 &&
+ (p_oggpacket->packet[0] & PACKET_TYPE_HEADER);
+ }
+ else return (p_oggpacket->granulepos == 0);
+}
+
/****************************************************************************
* Ogg_DecodePacket: Decode an Ogg packet.
****************************************************************************/
@@ -1398,8 +1346,16 @@ static void Ogg_DecodePacket( demux_t *p_demux,
p_stream->b_initializing = false;
}
- /* Convert the granulepos into the next pcr */
- Ogg_UpdatePCR( p_demux, p_stream, p_oggpacket );
+ mtime_t i_dts = Ogg_GranuleToTime( p_stream, p_oggpacket->granulepos, true, false );
+ mtime_t i_expected_dts = date_Get( &p_stream->dts ); /* Interpolated or previous end time */
+ if( i_dts == VLC_TS_INVALID )
+ i_dts = i_expected_dts;
+ else
+ date_Set( &p_stream->dts, i_dts );
+
+ /* Write end granule as next start, or do interpolation */
+ if( !Ogg_IsHeaderPacket( p_stream, p_oggpacket ) )
+ Ogg_SetNextFrame( p_demux, p_stream, p_oggpacket );
if( !b_selected )
{
@@ -1408,14 +1364,30 @@ static void Ogg_DecodePacket( demux_t *p_demux,
return;
}
- if( !( p_block = block_Alloc( p_oggpacket->bytes ) ) ) return;
+ if( !( p_block = block_Alloc( p_oggpacket->bytes ) ) )
+ return;
- DemuxDebug( msg_Dbg(p_demux, "block set from granule %"PRId64" to pts/pcr %"PRId64" skip %d",
- p_oggpacket->granulepos, p_stream->i_pcr, p_stream->i_skip_frames); )
+ /* Set effective timestamp */
+ if( i_dts != VLC_TS_INVALID )
+ p_block->i_dts = p_sys->i_nzpcr_offset + i_dts;
- if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
+ /* Vorbis and Opus can trim the end of a stream using granule positions. */
+ if( p_oggpacket->e_o_s )
+ {
+ mtime_t i_endtime = Ogg_GranuleToTime( p_stream, p_oggpacket->granulepos, false, false );
+ if( i_endtime != VLC_TS_INVALID && i_expected_dts != VLC_TS_INVALID )
+ {
+ p_block->i_length = i_endtime - i_expected_dts;
+ p_block->i_flags |= BLOCK_FLAG_END_OF_SEQUENCE;
+ }
+ }
+
+ if( p_stream->fmt.i_codec == VLC_CODEC_OPUS ) /* also required for trimming */
p_block->i_nb_samples = Ogg_OpusPacketDuration( p_oggpacket );
+ DemuxDebug( msg_Dbg(p_demux, "block set from granule %"PRId64" to pts/pcr %"PRId64" skip %d",
+ p_oggpacket->granulepos, p_block->i_dts, p_stream->i_skip_frames); )
+
/* may need to preroll after a seek or in case of preskip */
if ( p_stream->i_skip_frames > 0 )
{
@@ -1450,40 +1422,22 @@ static void Ogg_DecodePacket( demux_t *p_demux,
if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
{
- p_block->i_dts = Oggseek_GranuleToAbsTimestamp( p_stream, p_oggpacket->granulepos, false );
- p_block->i_pts = Oggseek_GranuleToAbsTimestamp( p_stream, p_oggpacket->granulepos, true );
- /* granulepos for dirac is possibly broken, this value should be ignored */
- if( 0 >= p_oggpacket->granulepos )
- {
- p_block->i_pts = VLC_TS_INVALID;
- p_block->i_dts = p_stream->i_pcr;
- }
+ if( p_oggpacket->granulepos > 0 )
+ p_block->i_pts = Ogg_GranuleToTime( p_stream, p_oggpacket->granulepos, true, true );
}
else if( p_stream->fmt.i_codec == VLC_CODEC_THEORA )
{
- p_block->i_pts =
- p_block->i_dts = p_stream->i_pcr;
- }
- else
- {
- p_block->i_pts = VLC_TS_INVALID;
- p_block->i_dts = p_stream->i_pcr;
+ p_block->i_pts = p_block->i_dts;
}
}
else if( p_stream->fmt.i_cat == AUDIO_ES )
{
- /* Blatant abuse of the i_length field. */
- if( p_stream->i_end_trim > 0 )
- {
- p_block->i_length = p_stream->i_end_trim * CLOCK_FREQ / p_stream->f_rate;
- p_block->i_flags |= BLOCK_FLAG_END_OF_SEQUENCE;
- }
- p_block->i_pts = p_block->i_dts = p_stream->i_pcr;
+ p_block->i_pts = p_block->i_dts;
}
else if( p_stream->fmt.i_cat == SPU_ES )
{
p_block->i_length = 0;
- p_block->i_pts = p_block->i_dts = p_stream->i_pcr;
+ p_block->i_pts = p_block->i_dts;
}
if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
@@ -1567,7 +1521,7 @@ static unsigned Ogg_OpusPacketDuration( ogg_packet *p_oggpacket )
****************************************************************************/
static int Ogg_FindLogicalStreams( demux_t *p_demux )
{
- demux_sys_t *p_ogg = p_demux->p_sys ;
+ demux_sys_t *p_ogg = p_demux->p_sys;
ogg_packet oggpacket;
p_ogg->i_total_length = stream_Size ( p_demux->s );
@@ -1593,6 +1547,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
es_format_Init( &p_stream->fmt, UNKNOWN_ES, 0 );
es_format_Init( &p_stream->fmt_old, UNKNOWN_ES, 0 );
p_stream->b_initializing = true;
+ p_stream->b_contiguous = true; /* default */
/* Setup the logical stream */
p_stream->i_serial_no = ogg_page_serialno( &p_ogg->current_page );
@@ -1633,9 +1588,10 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
es_format_Change( &p_stream->fmt, AUDIO_ES, VLC_CODEC_SPEEX );
if ( Ogg_ReadSpeexHeader( p_stream, &oggpacket ) )
msg_Dbg( p_demux, "found speex header, channels: %i, "
- "rate: %i, bitrate: %i, frames: %i group %i",
+ "rate: %"PRIu32"/%"PRIu32", bitrate: %i, frames: %i group %i",
p_stream->fmt.audio.i_channels,
- (int)p_stream->f_rate, p_stream->fmt.i_bitrate,
+ p_stream->dts.i_divider_num, p_stream->dts.i_divider_den,
+ p_stream->fmt.i_bitrate,
p_stream->special.speex.i_framesize,
p_stream->special.speex.i_framesperpacket );
else
@@ -1707,8 +1663,9 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
es_format_Change( &p_stream->fmt, VIDEO_ES, VLC_CODEC_THEORA );
if ( Ogg_ReadTheoraHeader( p_stream, &oggpacket ) )
msg_Dbg( p_demux,
- "found theora header, bitrate: %i, rate: %f",
- p_stream->fmt.i_bitrate, p_stream->f_rate );
+ "found theora header, bitrate: %i, rate: %"PRIu32"/%"PRIu32,
+ p_stream->fmt.i_bitrate,
+ p_stream->dts.i_divider_num, p_stream->dts.i_divider_den );
else
{
msg_Dbg( p_demux, "found invalid Theora header" );
@@ -1724,8 +1681,9 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
es_format_Change( &p_stream->fmt, VIDEO_ES, VLC_CODEC_DAALA );
if ( Ogg_ReadDaalaHeader( p_stream, &oggpacket ) )
msg_Dbg( p_demux,
- "found daala header, bitrate: %i, rate: %f",
- p_stream->fmt.i_bitrate, p_stream->f_rate );
+ "found daala header, bitrate: %i, rate: %"PRIu32"/%"PRIu32,
+ p_stream->fmt.i_bitrate,
+ p_stream->dts.i_divider_num, p_stream->dts.i_divider_den );
else
{
msg_Dbg( p_demux, "found invalid Daala header" );
@@ -1758,8 +1716,8 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
es_format_Change( &p_stream->fmt, VIDEO_ES, VLC_CODEC_VP8 );
if ( Ogg_ReadVP8Header( p_demux, p_stream, &oggpacket ) )
msg_Dbg( p_demux, "found VP8 header "
- "fps: %f, width:%i; height:%i",
- p_stream->f_rate,
+ "fps: %"PRIu32"/%"PRIu32", width:%i; height:%i",
+ p_stream->dts.i_divider_num, p_stream->dts.i_divider_den,
p_stream->fmt.video.i_width,
p_stream->fmt.video.i_height );
else
@@ -1807,6 +1765,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
{
/* Old header type */
p_stream->b_oggds = true;
+ p_stream->b_contiguous = false;
/* Check for video header (old format) */
if( GetDWLE((oggpacket.packet+96)) == 0x05589f80 &&
oggpacket.bytes >= 184 )
@@ -1819,13 +1778,12 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
msg_Dbg( p_demux, "found video header of type: %.4s",
(char *)&p_stream->fmt.i_codec );
- p_stream->fmt.video.i_frame_rate = 10000000;
- p_stream->fmt.video.i_frame_rate_base =
- GetQWLE((oggpacket.packet+164));
- p_stream->fmt.video.i_frame_rate_base =
- __MAX( p_stream->fmt.video.i_frame_rate_base, 1 );
- p_stream->f_rate = 10000000.0 /
- p_stream->fmt.video.i_frame_rate_base;
+ unsigned num = OGGDS_RESOLUTION;
+ unsigned den = GetQWLE(oggpacket.packet+164);
+ vlc_ureduce( &num, &den, num, den > 0 ? den : 1, OGGDS_RESOLUTION );
+ p_stream->fmt.video.i_frame_rate = num;
+ p_stream->fmt.video.i_frame_rate_base = den;
+ date_Init( &p_stream->dts, num, den );
p_stream->fmt.video.i_bits_per_pixel =
GetWLE((oggpacket.packet+182));
if( !p_stream->fmt.video.i_bits_per_pixel )
@@ -1841,12 +1799,20 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
p_stream->fmt.video.i_height;
msg_Dbg( p_demux,
- "fps: %f, width:%i; height:%i, bitcount:%i",
- p_stream->f_rate,
+ "fps: %u/%u, width:%i; height:%i, bitcount:%i",
+ p_stream->fmt.video.i_frame_rate,
+ p_stream->fmt.video.i_frame_rate_base,
p_stream->fmt.video.i_width,
p_stream->fmt.video.i_height,
p_stream->fmt.video.i_bits_per_pixel);
+ if ( !p_stream->fmt.video.i_frame_rate ||
+ !p_stream->fmt.video.i_frame_rate_base )
+ {
+ Ogg_LogicalStreamDelete( p_demux, p_stream );
+ p_stream = NULL;
+ p_ogg->i_streams--;
+ }
}
/* Check for audio header (old format) */
else if( GetDWLE((oggpacket.packet+96)) == 0x05589F81 )
@@ -1872,7 +1838,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
p_stream->fmt.audio.i_channels =
GetWLE((oggpacket.packet+126));
fill_channels_info(&p_stream->fmt.audio);
- p_stream->f_rate = p_stream->fmt.audio.i_rate =
+ p_stream->fmt.audio.i_rate =
GetDWLE((oggpacket.packet+128));
p_stream->fmt.i_bitrate =
GetDWLE((oggpacket.packet+132)) * 8;
@@ -1881,6 +1847,8 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
p_stream->fmt.audio.i_bitspersample =
GetWLE((oggpacket.packet+138));
+ date_Init( &p_stream->dts, p_stream->fmt.audio.i_rate, 1 );
+
wf_tag_to_fourcc( i_format_tag,
&p_stream->fmt.i_codec, 0 );
@@ -1900,7 +1868,8 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
p_stream->fmt.audio.i_rate,
p_stream->fmt.audio.i_bitspersample,
p_stream->fmt.i_bitrate / 1024 );
- if ( p_stream->f_rate == 0 )
+
+ if ( p_stream->fmt.audio.i_rate == 0 )
{
msg_Dbg( p_demux, "invalid oggds audio header" );
Ogg_LogicalStreamDelete( p_demux, p_stream );
@@ -1924,6 +1893,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
stream_header_t *st = &tmp;
p_stream->b_oggds = true;
+ p_stream->b_contiguous = false;
memcpy( st->streamtype, &oggpacket.packet[1+0], 8 );
memcpy( st->subtype, &oggpacket.packet[1+8], 4 );
@@ -1952,11 +1922,14 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
msg_Dbg( p_demux, "found video header of type: %.4s",
(char *)&p_stream->fmt.i_codec );
- p_stream->fmt.video.i_frame_rate = 10000000;
- p_stream->fmt.video.i_frame_rate_base = st->time_unit;
if( st->time_unit <= 0 )
st->time_unit = 400000;
- p_stream->f_rate = 10000000.0 / st->time_unit;
+ unsigned num,den;
+ vlc_ureduce( &num, &den, OGGDS_RESOLUTION, st->time_unit,
+ OGGDS_RESOLUTION );
+ date_Init( &p_stream->dts, num, den );
+ p_stream->fmt.video.i_frame_rate = num;
+ p_stream->fmt.video.i_frame_rate_base = den;
p_stream->fmt.video.i_bits_per_pixel = st->bits_per_sample;
p_stream->fmt.video.i_width = st->sh.video.width;
p_stream->fmt.video.i_height = st->sh.video.height;
@@ -1966,8 +1939,9 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
p_stream->fmt.video.i_height;
msg_Dbg( p_demux,
- "fps: %f, width:%i; height:%i, bitcount:%i",
- p_stream->f_rate,
+ "fps: %u/%u, width:%i; height:%i, bitcount:%i",
+ p_stream->fmt.video.i_frame_rate,
+ p_stream->fmt.video.i_frame_rate_base,
p_stream->fmt.video.i_width,
p_stream->fmt.video.i_height,
p_stream->fmt.video.i_bits_per_pixel );
@@ -2008,9 +1982,13 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
i_format_tag = strtol(p_buffer,NULL,16);
p_stream->fmt.audio.i_channels = st->sh.audio.channels;
fill_channels_info(&p_stream->fmt.audio);
- if( st->time_unit <= 0 )
- st->time_unit = 10000000;
- p_stream->f_rate = p_stream->fmt.audio.i_rate = st->samples_per_unit * 10000000 / st->time_unit;
+ unsigned num,den;
+ vlc_ureduce( &num, &den,
+ st->samples_per_unit * OGGDS_RESOLUTION,
+ st->time_unit > 0 ? st->time_unit : OGGDS_RESOLUTION,
+ OGGDS_RESOLUTION );
+ date_Init( &p_stream->dts, num, den );
+ p_stream->fmt.audio.i_rate = num / den;
p_stream->fmt.i_bitrate = st->sh.audio.avgbytespersec * 8;
p_stream->fmt.audio.i_blockalign = st->sh.audio.blockalign;
p_stream->fmt.audio.i_bitspersample = st->bits_per_sample;
@@ -2034,7 +2012,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
p_stream->fmt.audio.i_rate,
p_stream->fmt.audio.i_bitspersample,
p_stream->fmt.i_bitrate / 1024 );
- if ( p_stream->f_rate == 0 )
+ if ( p_stream->fmt.audio.i_rate == 0 )
{
msg_Dbg( p_demux, "invalid oggds audio header" );
Ogg_LogicalStreamDelete( p_demux, p_stream );
@@ -2050,7 +2028,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
msg_Dbg( p_demux, "found text subtitle header" );
es_format_Change( &p_stream->fmt, SPU_ES, VLC_CODEC_SUBT );
- p_stream->f_rate = 1000; /* granulepos is in millisec */
+ date_Init( &p_stream->dts, 1000, 1 ); /* granulepos is in millisec */
}
else
{
@@ -2075,8 +2053,9 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
{
if ( Ogg_ReadOggSpotsHeader( p_stream, &oggpacket ) )
msg_Dbg( p_demux,
- "found OggSpots header, time resolution: %f",
- p_stream->f_rate );
+ "found OggSpots header, time resolution: %u/%u",
+ p_stream->fmt.video.i_frame_rate,
+ p_stream->fmt.video.i_frame_rate_base );
else
{
msg_Err( p_demux, "found invalid OggSpots header" );
@@ -2219,8 +2198,7 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
else
p_ogg->i_bitrate += p_stream->fmt.i_bitrate;
- p_stream->i_pcr = p_stream->i_previous_pcr = VLC_TS_UNKNOWN;
- p_stream->i_previous_granulepos = -1;
+ p_stream->i_pcr = VLC_TS_UNKNOWN;
p_stream->b_reinit = false;
}
@@ -2644,8 +2622,9 @@ static bool Ogg_ReadTheoraHeader( logical_stream_t *p_stream,
i_version = i_major * 1000000 + i_minor * 1000 + i_subminor;
p_stream->i_keyframe_offset = 0;
- p_stream->f_rate = ((double)i_fps_numerator) / i_fps_denominator;
- if ( p_stream->f_rate == 0 ) return false;
+ if ( !i_fps_denominator || !i_fps_numerator )
+ return false;
+ date_Init( &p_stream->dts, i_fps_numerator, i_fps_denominator );
if ( i_version >= 3002001 )
{
@@ -2708,8 +2687,9 @@ static bool Ogg_ReadDaalaHeader( logical_stream_t *p_stream,
i_version = i_major * 1000000 + i_minor * 1000 + i_subminor;
VLC_UNUSED(i_version);
p_stream->i_keyframe_offset = 0;
- p_stream->f_rate = ((double)i_timebase_numerator) / i_timebase_denominator;
- if ( p_stream->f_rate == 0 ) return false;
+ if ( !i_timebase_numerator || !i_timebase_denominator )
+ return false;
+ date_Init( &p_stream->dts, i_timebase_numerator, i_timebase_denominator );
return true;
}
@@ -2729,12 +2709,14 @@ static bool Ogg_ReadVorbisHeader( logical_stream_t *p_stream,
oggpack_adv( &opb, 88 );
p_stream->fmt.audio.i_channels = oggpack_read( &opb, 8 );
fill_channels_info(&p_stream->fmt.audio);
- p_stream->f_rate = p_stream->fmt.audio.i_rate =
- oggpack_read( &opb, 32 );
+ p_stream->fmt.audio.i_rate = oggpack_read( &opb, 32 );
+ if( p_stream->fmt.audio.i_rate == 0 )
+ return false;
+ date_Init( &p_stream->dts, p_stream->fmt.audio.i_rate, 1 );
+
oggpack_adv( &opb, 32 );
p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 ); /* is signed 32 */
if( p_stream->fmt.i_bitrate > INT32_MAX ) p_stream->fmt.i_bitrate = 0;
- if ( p_stream->f_rate == 0 ) return false;
return true;
}
#ifdef HAVE_LIBVORBIS
@@ -2788,8 +2770,10 @@ static bool Ogg_ReadSpeexHeader( logical_stream_t *p_stream,
oggpack_adv( &opb, 224 );
oggpack_adv( &opb, 32 ); /* speex_version_id */
oggpack_adv( &opb, 32 ); /* header_size */
- p_stream->f_rate = p_stream->fmt.audio.i_rate = oggpack_read( &opb, 32 );
- if ( p_stream->f_rate == 0 ) return false;
+ p_stream->fmt.audio.i_rate = oggpack_read( &opb, 32 );
+ if ( !p_stream->fmt.audio.i_rate )
+ return false;
+ date_Init( &p_stream->dts, p_stream->fmt.audio.i_rate, 1 );
oggpack_adv( &opb, 32 ); /* mode */
oggpack_adv( &opb, 32 ); /* mode_bitstream_version */
p_stream->fmt.audio.i_channels = oggpack_read( &opb, 32 );
@@ -2816,7 +2800,8 @@ static void Ogg_ReadOpusHeader( logical_stream_t *p_stream,
/* All OggOpus streams are timestamped at 48kHz and
* can be played at 48kHz. */
- p_stream->f_rate = p_stream->fmt.audio.i_rate = 48000;
+ p_stream->fmt.audio.i_rate = 48000;
+ date_Init( &p_stream->dts, p_stream->fmt.audio.i_rate, 1 );
p_stream->fmt.i_bitrate = 0;
/* Cheat and get additional info ;) */
@@ -2852,13 +2837,15 @@ static bool Ogg_ReadFlacStreamInfo( demux_t *p_demux, logical_stream_t *p_stream
if( bs_read( &s, 24 ) >= 34 /*size STREAMINFO*/ )
{
bs_skip( &s, 80 );
- p_stream->f_rate = p_stream->fmt.audio.i_rate = bs_read( &s, 20 );
+ p_stream->fmt.audio.i_rate = bs_read( &s, 20 );
p_stream->fmt.audio.i_channels = bs_read( &s, 3 ) + 1;
fill_channels_info(&p_stream->fmt.audio);
- msg_Dbg( p_demux, "FLAC header, channels: %i, rate: %i",
- p_stream->fmt.audio.i_channels, (int)p_stream->f_rate );
- if ( p_stream->f_rate == 0 ) return false;
+ msg_Dbg( p_demux, "FLAC header, channels: %"PRIu8", rate: %u",
+ p_stream->fmt.audio.i_channels, p_stream->fmt.audio.i_rate );
+ if ( p_stream->fmt.audio.i_rate == 0 )
+ return false;
+ date_Init( &p_stream->dts, p_stream->fmt.audio.i_rate, 1 );
}
else
{
@@ -2894,8 +2881,9 @@ static bool Ogg_ReadKateHeader( logical_stream_t *p_stream,
gnum = oggpack_read( &opb, 32 );
gden = oggpack_read( &opb, 32 );
gden = __MAX( gden, 1 );
- p_stream->f_rate = (double)gnum/gden;
- if ( p_stream->f_rate == 0 ) return false;
+ if ( !gnum || !gden )
+ return false;
+ date_Init( &p_stream->dts, gnum, gden );
p_stream->fmt.psz_language = malloc(16);
if( p_stream->fmt.psz_language )
@@ -2952,10 +2940,10 @@ static bool Ogg_ReadVP8Header( demux_t *p_demux, logical_stream_t *p_stream,
p_stream->fmt.video.i_sar_den = GetDWBE( &p_oggpacket->packet[15 - 1] ) & 0x0FFF;
p_stream->fmt.video.i_frame_rate = GetDWBE( &p_oggpacket->packet[18] );
p_stream->fmt.video.i_frame_rate_base = GetDWBE( &p_oggpacket->packet[22] );
- p_stream->fmt.video.i_frame_rate_base =
- __MAX( p_stream->fmt.video.i_frame_rate_base, 1 );
- p_stream->f_rate = (double) p_stream->fmt.video.i_frame_rate / p_stream->fmt.video.i_frame_rate_base;
- if ( p_stream->f_rate == 0 ) return false;
+ if ( !p_stream->fmt.video.i_frame_rate || !p_stream->fmt.video.i_frame_rate_base )
+ return false;
+ date_Init( &p_stream->dts, p_stream->fmt.video.i_frame_rate,
+ p_stream->fmt.video.i_frame_rate_base );
return true;
/* METADATA */
case 0x02:
@@ -3095,8 +3083,8 @@ static void Ogg_ReadAnnodexHeader( demux_t *p_demux,
granule_rate_numerator, granule_rate_denominator,
p_stream->i_secondary_header_packets, content_type_string );
- p_stream->f_rate = (float) granule_rate_numerator /
- (float) granule_rate_denominator;
+ if( granule_rate_numerator && granule_rate_denominator )
+ date_Init( &p_stream->dts, granule_rate_numerator, granule_rate_denominator );
/* What type of file do we have?
* strcmp is safe to use here because we've extracted
@@ -3425,8 +3413,17 @@ static bool Ogg_ReadDiracHeader( logical_stream_t *p_stream,
u_d = dirac_uint( &bs ); /* frame_rate_denominator */
}
}
- p_stream->f_rate = (float) u_n / u_d;
- if ( p_stream->f_rate == 0 ) return false;
+
+ if( !u_n || !u_d )
+ return false;
+
+ /*
+ * NB, OggDirac granulepos values are in units of 2*picturerate
+ * When picture_coding_mode = 0 (progressive),
+ * pt increments by two for each picture in display order.
+ * When picture_coding_mode = 1 (interlace),
+ * pt increments by one for each field in display order. */
+ date_Init( &p_stream->dts, 2 * u_n, u_d );
return true;
}
@@ -3477,17 +3474,17 @@ static bool Ogg_ReadOggSpotsHeader( logical_stream_t *p_stream,
i_granulerate_denominator = 1;
}
- p_stream->f_rate = ((double)i_granulerate_numerator) / i_granulerate_denominator;
- if ( p_stream->f_rate == 0 )
- {
+ if ( !i_granulerate_numerator || !i_granulerate_denominator )
return false;
- }
/* Normalize granulerate */
vlc_ureduce(&p_stream->fmt.video.i_frame_rate,
&p_stream->fmt.video.i_frame_rate_base,
i_granulerate_numerator, i_granulerate_denominator, 0);
+ date_Init( &p_stream->dts, p_stream->fmt.video.i_frame_rate,
+ p_stream->fmt.video.i_frame_rate_base );
+
p_stream->i_granule_shift = p_oggpacket->packet[28];
return true;
diff --git a/modules/demux/ogg.h b/modules/demux/ogg.h
index 13c1c6d4d6..1914762e41 100644
--- a/modules/demux/ogg.h
+++ b/modules/demux/ogg.h
@@ -22,14 +22,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifdef HAVE_LIBVORBIS
- #include <vorbis/codec.h>
-#endif
-
/*****************************************************************************
* Definitions of structures and functions used by this plugin
*****************************************************************************/
@@ -48,6 +40,8 @@
#define PACKET_LEN_BITS2 0x02
#define PACKET_IS_SYNCPOINT 0x08
+#define OGGDS_RESOLUTION 10000000
+
typedef struct oggseek_index_entry demux_index_entry_t;
typedef struct ogg_skeleton_t ogg_skeleton_t;
@@ -64,7 +58,8 @@ typedef struct logical_stream_s
es_format_t fmt;
es_format_t fmt_old; /* format of old ES is reused */
es_out_id_t *p_es;
- double f_rate;
+ date_t dts;
+ bool b_contiguous; /* Granule is end of packet */
int i_serial_no;
@@ -76,13 +71,11 @@ typedef struct logical_stream_s
int32_t i_extra_headers_packets;
void *p_headers;
int i_headers;
- ogg_int64_t i_previous_granulepos;
ogg_int64_t i_granulepos_offset;/* first granule offset */
/* program clock reference (in units of 90kHz) derived from the previous
* granulepos */
mtime_t i_pcr;
- mtime_t i_previous_pcr;
/* Misc */
bool b_initializing;
@@ -93,8 +86,6 @@ typedef struct logical_stream_s
/* Opus has a starting offset in the headers. */
int i_pre_skip;
- /* Vorbis and Opus can trim the end of a stream using granule positions. */
- int i_end_trim; /* number of samples to keep */
/* offset of first keyframe for theora; can be 0 or 1 depending on version number */
int8_t i_keyframe_offset;
diff --git a/modules/demux/ogg_granule.c b/modules/demux/ogg_granule.c
new file mode 100644
index 0000000000..524533dd87
--- /dev/null
+++ b/modules/demux/ogg_granule.c
@@ -0,0 +1,187 @@
+/*****************************************************************************
+ * ogg_granule.c : ogg granule functions
+ *****************************************************************************
+ * Copyright (C) 2008 - 2018 VideoLAN Authors and VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_LIBVORBIS
+ #include <vorbis/codec.h>
+#endif
+
+#include <ogg/ogg.h>
+
+#include <vlc_common.h>
+#include <vlc_codecs.h>
+#include <vlc_es.h>
+
+#include "ogg.h"
+#include "ogg_granule.h"
+
+/* Theora spec 7.1 */
+#define THEORA_FTYPE_NOTDATA 0x80
+#define THEORA_FTYPE_INTERFRAME 0x40
+
+/* Checks if current packet matches codec keyframe */
+bool Ogg_IsKeyFrame( const logical_stream_t *p_stream, const ogg_packet *p_packet )
+{
+ if ( p_stream->b_oggds )
+ {
+ return ( p_packet->bytes > 0 && p_packet->packet[0] & PACKET_IS_SYNCPOINT );
+ }
+ else switch ( p_stream->fmt.i_codec )
+ {
+ case VLC_CODEC_THEORA:
+ case VLC_CODEC_DAALA: /* Same convention used in daala */
+ if ( p_packet->bytes <= 0 || p_packet->packet[0] & THEORA_FTYPE_NOTDATA )
+ return false;
+ else
+ return !( p_packet->packet[0] & THEORA_FTYPE_INTERFRAME );
+ case VLC_CODEC_VP8:
+ return ( ( ( p_packet->granulepos >> 3 ) & 0x07FFFFFF ) == 0 );
+ case VLC_CODEC_DIRAC:
+ return ( p_packet->granulepos & 0xFF8000FF );
+ default:
+ return true;
+ }
+}
+
+int64_t Ogg_GetKeyframeGranule( const logical_stream_t *p_stream, int64_t i_granule )
+{
+ if ( p_stream->b_oggds )
+ {
+ return -1; /* We have no way to know */
+ }
+ else switch( p_stream->fmt.i_codec )
+ {
+ case VLC_CODEC_THEORA:
+ case VLC_CODEC_DAALA:
+ return ( i_granule >> p_stream->i_granule_shift ) << p_stream->i_granule_shift;
+ case VLC_CODEC_DIRAC:
+ return ( i_granule >> 31 ) << 31;
+ default:
+ /* No change, that's keyframe */
+ return i_granule;
+ }
+}
+
+static int64_t Ogg_GranuleToSampleDelta( const logical_stream_t *p_stream, int64_t i_granule )
+{
+ if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
+ return (i_granule >> 9) & 0x1fff;
+ else
+ return -1;
+}
+
+static int64_t Ogg_GranuleToSample( const logical_stream_t *p_stream, int64_t i_granule )
+{
+ switch( p_stream->fmt.i_codec )
+ {
+ case VLC_CODEC_THEORA:
+ case VLC_CODEC_DAALA:
+ case VLC_CODEC_KATE:
+ {
+ ogg_int64_t iframe = i_granule >> p_stream->i_granule_shift;
+ ogg_int64_t pframe = i_granule - ( iframe << p_stream->i_granule_shift );
+ return iframe + pframe;
+ }
+ case VLC_CODEC_VP8:
+ case VLC_CODEC_OGGSPOTS:
+ return i_granule >> p_stream->i_granule_shift;
+ case VLC_CODEC_DIRAC:
+ return (i_granule >> 31);
+ case VLC_CODEC_OPUS:
+ case VLC_CODEC_VORBIS:
+ case VLC_CODEC_SPEEX:
+ case VLC_CODEC_FLAC:
+ return i_granule/* - p_stream->i_pre_skip*/;
+ default:
+ return i_granule;
+ }
+}
+
+static int64_t Ogg_ShiftPacketSample( const logical_stream_t *p_stream,
+ int64_t i_sample, bool b_start )
+{
+ /* /!\ Packet Granule as sample value ! */
+
+ /* granule always point to end time of packet
+ Except with OggDS where it is reversed */
+ int64_t i_endtostartoffset = 0; /* in interval # */
+ if( p_stream->b_oggds )
+ i_endtostartoffset = (b_start ? 0 : 1);
+ else
+ i_endtostartoffset = (b_start ? -1 : 0);
+
+ if( p_stream->fmt.i_cat == VIDEO_ES )
+ {
+ if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC ) /* points to start */
+ i_sample += (p_stream->special.dirac.b_interlaced ? 1 : 2) * (i_endtostartoffset + 1);
+ else
+ i_sample += i_endtostartoffset * 1;
+ }
+ else if( p_stream->fmt.i_cat == AUDIO_ES )
+ {
+ if( p_stream->fmt.i_codec == VLC_CODEC_SPEEX )
+ {
+ i_sample += i_endtostartoffset *
+ p_stream->special.speex.i_framesize *
+ p_stream->special.speex.i_framesperpacket;
+ }
+ else /* we can't tell */
+ {
+ if( i_endtostartoffset != 0 )
+ return -1;
+ }
+ }
+ return i_sample;
+}
+
+mtime_t Ogg_SampleToTime( const logical_stream_t *p_stream, int64_t i_sample, bool b_start )
+{
+ i_sample = Ogg_ShiftPacketSample( p_stream, i_sample, b_start );
+ if( i_sample < 0 )
+ return VLC_TS_INVALID;
+
+ date_t d = p_stream->dts;
+ date_Set(&d, VLC_TS_0);
+ return date_Increment( &d, i_sample );
+}
+
+bool Ogg_GranuleIsValid( const logical_stream_t *p_stream, int64_t i_granule )
+{
+ /* First frame in ogm is 0 (0[header] 0[frame] -1 2 3 -1 5 ...) */
+ return !( i_granule < 1 - !!p_stream->b_oggds );
+}
+
+mtime_t Ogg_GranuleToTime( const logical_stream_t *p_stream, int64_t i_granule,
+ bool b_start, bool b_pts )
+{
+ if( !Ogg_GranuleIsValid( p_stream, i_granule ) )
+ return VLC_TS_INVALID;
+
+ int64_t i_sample = Ogg_GranuleToSample( p_stream, i_granule );
+ if( b_pts )
+ {
+ int64_t i_delta = Ogg_GranuleToSampleDelta( p_stream, i_granule );
+ if( i_delta != -1 )
+ i_sample += i_delta;
+ }
+ return Ogg_SampleToTime( p_stream, i_sample, b_start );
+}
diff --git a/modules/demux/ogg_granule.h b/modules/demux/ogg_granule.h
new file mode 100644
index 0000000000..2bdf409e29
--- /dev/null
+++ b/modules/demux/ogg_granule.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+ * ogg_granule.h : ogg granule functions
+ *****************************************************************************
+ * Copyright (C) 2008 - 2018 VideoLAN Authors and VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+int64_t Ogg_GetKeyframeGranule ( const logical_stream_t *, int64_t i_granule );
+bool Ogg_IsKeyFrame ( const logical_stream_t *, const ogg_packet * );
+mtime_t Ogg_GranuleToTime( const logical_stream_t *, int64_t i_granule,
+ bool b_packetstart, bool b_pts );
+mtime_t Ogg_SampleToTime( const logical_stream_t *, int64_t i_sample,
+ bool b_packetstart );
+bool Ogg_GranuleIsValid( const logical_stream_t *, int64_t i_granule );
diff --git a/modules/demux/oggseek.c b/modules/demux/oggseek.c
index ff4c5f7f7b..3e774c79ea 100644
--- a/modules/demux/oggseek.c
+++ b/modules/demux/oggseek.c
@@ -30,6 +30,10 @@
# include "config.h"
#endif
+#ifdef HAVE_LIBVORBIS
+ #include <vorbis/codec.h>
+#endif
+
#include <vlc_common.h>
#include <vlc_demux.h>
@@ -40,10 +44,7 @@
#include "ogg.h"
#include "oggseek.h"
-
-/* Theora spec 7.1 */
-#define THEORA_FTYPE_NOTDATA 0x80
-#define THEORA_FTYPE_INTERFRAME 0x40
+#include "ogg_granule.h"
#define SEGMENT_NOT_FOUND -1
@@ -55,14 +56,6 @@ typedef struct packetStartCoordinates
int64_t i_skip;
} packetStartCoordinates;
-//#define OGG_SEEK_DEBUG 1
-#ifdef OGG_SEEK_DEBUG
- #define OggDebug(code) code
- #define OggNoDebug(code)
-#else
- #define OggDebug(code)
- #define OggNoDebug(code) code
-#endif
/************************************************************
* index entries
*************************************************************/
@@ -289,7 +282,8 @@ void Oggseek_ProbeEnd( demux_t *p_demux )
if ( p_sys->pp_stream[i]->i_serial_no != ogg_page_serialno( &page ) )
continue;
- i_length = Oggseek_GranuleToAbsTimestamp( p_sys->pp_stream[i], i_granule, false );
+ i_length = Ogg_GranuleToTime( p_sys->pp_stream[i], i_granule,
+ !p_sys->pp_stream[i]->b_contiguous, false );
if( i_length > VLC_TS_INVALID )
p_sys->i_length = __MAX( p_sys->i_length, (i_length - VLC_TS_0) / 1000000 );
break;
@@ -441,49 +435,6 @@ static int64_t find_first_page_granule( demux_t *p_demux,
}
}
-/* Checks if current packet matches codec keyframe */
-bool Ogg_IsKeyFrame( logical_stream_t *p_stream, ogg_packet *p_packet )
-{
- if ( p_stream->b_oggds )
- {
- return ( p_packet->bytes > 0 && p_packet->packet[0] & PACKET_IS_SYNCPOINT );
- }
- else switch ( p_stream->fmt.i_codec )
- {
- case VLC_CODEC_THEORA:
- case VLC_CODEC_DAALA: /* Same convention used in daala */
- if ( p_packet->bytes <= 0 || p_packet->packet[0] & THEORA_FTYPE_NOTDATA )
- return false;
- else
- return !( p_packet->packet[0] & THEORA_FTYPE_INTERFRAME );
- case VLC_CODEC_VP8:
- return ( ( ( p_packet->granulepos >> 3 ) & 0x07FFFFFF ) == 0 );
- case VLC_CODEC_DIRAC:
- return ( p_packet->granulepos & 0xFF8000FF );
- default:
- return true;
- }
-}
-
-int64_t Ogg_GetKeyframeGranule( logical_stream_t *p_stream, int64_t i_granule )
-{
- if ( p_stream->b_oggds )
- {
- return -1; /* We have no way to know */
- }
- else if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
- p_stream->fmt.i_codec == VLC_CODEC_DAALA )
- {
- return ( i_granule >> p_stream->i_granule_shift ) << p_stream->i_granule_shift;
- }
- else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
- {
- return ( i_granule >> 31 ) << 31;
- }
- /* No change, that's keyframe or it can't be shifted out (oggds) */
- return i_granule;
-}
-
static bool OggSeekToPacket( demux_t *p_demux, logical_stream_t *p_stream,
int64_t i_granulepos, packetStartCoordinates *p_lastpacketcoords,
bool b_exact )
@@ -674,82 +625,6 @@ restart:
return i_result;
}
-/* Dont use b_presentation with frames granules ! */
-mtime_t Oggseek_GranuleToAbsTimestamp( logical_stream_t *p_stream,
- int64_t i_granule, bool b_presentation )
-{
- mtime_t i_timestamp = VLC_TS_INVALID;
- if ( i_granule < 1 - !!p_stream->b_oggds )
- return VLC_TS_INVALID;
-
- if ( p_stream->b_oggds )
- {
- i_timestamp = i_granule * CLOCK_FREQ / p_stream->f_rate;
- }
- else switch( p_stream->fmt.i_codec )
- {
- case VLC_CODEC_THEORA:
- case VLC_CODEC_DAALA:
- case VLC_CODEC_KATE:
- {
- ogg_int64_t iframe = i_granule >> p_stream->i_granule_shift;
- ogg_int64_t pframe = i_granule - ( iframe << p_stream->i_granule_shift );
- /* See Theora A.2.3 */
- if ( b_presentation ) pframe -= p_stream->i_keyframe_offset;
- i_timestamp = ( iframe + pframe ) * CLOCK_FREQ / p_stream->f_rate;
- break;
- }
- case VLC_CODEC_VP8:
- {
- ogg_int64_t frame = i_granule >> p_stream->i_granule_shift;
- if ( b_presentation ) frame--;
- i_timestamp = frame * CLOCK_FREQ / p_stream->f_rate;
- break;
- }
- case VLC_CODEC_DIRAC:
- {
- ogg_int64_t i_dts = i_granule >> 31;
- ogg_int64_t delay = (i_granule >> 9) & 0x1fff;
- /* NB, OggDirac granulepos values are in units of 2*picturerate */
- double f_rate = p_stream->f_rate;
- if ( !p_stream->special.dirac.b_interlaced ) f_rate *= 2;
- if ( b_presentation ) i_dts += delay;
- i_timestamp = i_dts * CLOCK_FREQ / f_rate;
- break;
- }
- case VLC_CODEC_OPUS:
- {
- if ( b_presentation ) return VLC_TS_INVALID;
- i_timestamp = ( i_granule - p_stream->i_pre_skip ) * CLOCK_FREQ / 48000;
- break;
- }
- case VLC_CODEC_VORBIS:
- case VLC_CODEC_FLAC:
- {
- if ( b_presentation ) return VLC_TS_INVALID;
- i_timestamp = i_granule * CLOCK_FREQ / p_stream->f_rate;
- break;
- }
- case VLC_CODEC_SPEEX:
- {
- if ( b_presentation )
- i_granule -= p_stream->special.speex.i_framesize *
- p_stream->special.speex.i_framesperpacket;
- i_timestamp = i_granule * CLOCK_FREQ / p_stream->f_rate;
- break;
- }
- case VLC_CODEC_OGGSPOTS:
- {
- if ( b_presentation ) return VLC_TS_INVALID;
- i_timestamp = ( i_granule >> p_stream->i_granule_shift )
- * CLOCK_FREQ / p_stream->f_rate;
- break;
- }
- }
-
- return i_timestamp != VLC_TS_INVALID ? i_timestamp + VLC_TS_0 : VLC_TS_INVALID;
-}
-
/* returns pos */
static int64_t OggBisectSearchByTime( demux_t *p_demux, logical_stream_t *p_stream,
mtime_t i_targettime, int64_t i_pos_lower, int64_t i_pos_upper)
@@ -803,14 +678,18 @@ static int64_t OggBisectSearchByTime( demux_t *p_demux, logical_stream_t *p_stre
p_stream,
¤t.i_granule );
- current.i_timestamp = Oggseek_GranuleToAbsTimestamp( p_stream,
- current.i_granule, false );
+ current.i_timestamp = Ogg_GranuleToTime( p_stream, current.i_granule,
+ !p_stream->b_contiguous, false );
if ( current.i_timestamp == VLC_TS_INVALID && current.i_granule > 0 )
{
msg_Err( p_demux, "Unmatched granule. New codec ?" );
return -1;
}
+ else if ( current.i_timestamp < 0 ) /* due to preskip with some codecs */
+ {
+ current.i_timestamp = 0;
+ }
if ( current.i_pos != -1 && current.i_granule != -1 )
{
@@ -874,7 +753,7 @@ static int64_t OggBisectSearchByTime( demux_t *p_demux, logical_stream_t *p_stre
i_keyframegranule >> p_stream->i_granule_shift,
bestlower.i_granule,
i_pos_upper,
- Oggseek_GranuleToAbsTimestamp( p_stream, i_keyframegranule, false ) ) );
+ Ogg_GranuleToTime( p_stream, i_keyframegranule, !p_stream->b_contiguous, false ) ) );
OggDebug( msg_Dbg( p_demux, "Seeking back to %"PRId64, __MAX ( bestlower.i_pos - OGGSEEK_BYTES_TO_READ, p_stream->i_data_start ) ) );
diff --git a/modules/demux/oggseek.h b/modules/demux/oggseek.h
index 4225a13472..93755555ee 100644
--- a/modules/demux/oggseek.h
+++ b/modules/demux/oggseek.h
@@ -26,6 +26,15 @@
* Preamble
*****************************************************************************/
+//#define OGG_SEEK_DEBUG 1
+#ifdef OGG_SEEK_DEBUG
+ #define OggDebug(code) code
+ #define OggNoDebug(code)
+#else
+ #define OggDebug(code)
+ #define OggNoDebug(code) code
+#endif
+
#define PAGE_HEADER_BYTES 27
#define OGGSEEK_BYTES_TO_READ 8500
@@ -49,11 +58,6 @@ struct oggseek_index_entry
int64_t i_pagepos_end;
};
-int64_t Ogg_GetKeyframeGranule ( logical_stream_t *p_stream, int64_t i_granule );
-bool Ogg_IsKeyFrame ( logical_stream_t *, ogg_packet * );
-
-mtime_t Oggseek_GranuleToAbsTimestamp ( logical_stream_t *p_stream, int64_t i_granule,
- bool b_presentation );
int Oggseek_BlindSeektoAbsoluteTime ( demux_t *, logical_stream_t *, mtime_t, bool );
int Oggseek_BlindSeektoPosition ( demux_t *, logical_stream_t *, double f, bool );
int Oggseek_SeektoAbsolutetime ( demux_t *, logical_stream_t *, mtime_t );
More information about the vlc-commits
mailing list