#include <vlc_codecs.h>
#include <vlc_bits.h>
#include "xiph.h"
-#include "vorbis.h"
-#include "kate_categories.h"
+#include "xiph_metadata.h"
#include "ogg.h"
#include "oggseek.h"
static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *p_stream );
/* */
-static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8_t *p_headers, int i_headers );
+static void Ogg_ExtractMeta( demux_t *p_demux, es_format_t *p_fmt, const uint8_t *p_headers, int i_headers );
static int64_t Ogg_GetLastPacket( demux_t *p_demux, logical_stream_t *p_stream, double f_rate );
/* Logical bitstream headers */
static void Ogg_ReadAnnodexHeader( demux_t *, logical_stream_t *, ogg_packet * );
static bool Ogg_ReadDiracHeader( logical_stream_t *, ogg_packet * );
+static void fill_channels_info(audio_format_t *audio)
+{
+ static const int pi_channels_map[9] =
+ {
+ 0,
+ AOUT_CHAN_CENTER,
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
+ AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
+ | AOUT_CHAN_REARRIGHT,
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
+ | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
+ | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE,
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
+ | AOUT_CHAN_REARCENTER | AOUT_CHAN_MIDDLELEFT
+ | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE,
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT
+ | AOUT_CHAN_REARRIGHT | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT
+ | AOUT_CHAN_LFE,
+ };
+
+ unsigned chans = audio->i_channels;
+ if (chans < sizeof(pi_channels_map) / sizeof(pi_channels_map[0]))
+ audio->i_physical_channels =
+ audio->i_original_channels = pi_channels_map[chans];
+}
+
/*****************************************************************************
* Open: initializes ogg demux structures
*****************************************************************************/
return VLC_EGENERIC;
*pi_int = p_sys->i_attachments;
- *ppp_attach = xmalloc( sizeof(input_attachment_t**) * p_sys->i_attachments );
+ *ppp_attach = xmalloc( sizeof(input_attachment_t*) * p_sys->i_attachments );
for( int i = 0; i < p_sys->i_attachments; i++ )
(*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] );
return VLC_SUCCESS;
if( p_sys->i_seekpoints > 0 )
{
*pi_int = 1;
- *ppp_title = malloc( sizeof( input_title_t**) );
+ *ppp_title = malloc( sizeof( input_title_t* ) );
input_title_t *p_title = (*ppp_title)[0] = vlc_input_title_New();
for( int i = 0; i < p_sys->i_seekpoints; i++ )
{
}
Ogg_ResetStreamHelper( p_sys );
- int64_t i_block = p_sys->pp_seekpoints[i_seekpoint]->i_time_offset * p_sys->i_bitrate / INT64_C(8000000);
- if( stream_Seek( p_demux->s, i_block ) )
- return VLC_EGENERIC;
+
+ if ( p_sys->i_bitrate == 0 || p_sys->b_partial_bitrate )
+ {
+ /* we won't be able to find block by time
+ * we'll need to bisect search from here
+ * or use skeleton index if any (FIXME)
+ */
+ if ( p_sys->pp_stream[0]->fmt.i_codec == VLC_CODEC_OPUS )
+ {
+ /* Granule = Freq * T + pre-skip */
+ oggseek_find_frame ( p_demux, p_sys->pp_stream[0],
+ ( p_sys->pp_seekpoints[i_seekpoint]->i_time_offset * 0.048 + p_sys->pp_stream[0]->i_pre_skip ) );
+ }
+ else return VLC_EGENERIC;
+ }
+ else
+ {
+ int64_t i_block = p_sys->pp_seekpoints[i_seekpoint]->i_time_offset * p_sys->i_bitrate / INT64_C(8000000);
+ if( stream_Seek( p_demux->s, i_block ) )
+ return VLC_EGENERIC;
+ }
+ p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
+ p_demux->info.i_seekpoint = i_seekpoint;
return VLC_SUCCESS;
}
p_stream->p_es, &p_stream->fmt );
if( p_stream->i_headers > 0 )
- Ogg_ExtractMeta( p_demux, p_stream->fmt.i_codec,
+ Ogg_ExtractMeta( p_demux, & p_stream->fmt,
p_stream->p_headers, p_stream->i_headers );
/* we're not at BOS anymore for this logical stream */
if( i_pts == VLC_TS_INVALID ) i_pts = VLC_TS_0;
else if( i_pts == -1 && i_interpolated_pts == VLC_TS_INVALID )
i_pts = VLC_TS_0;
- else if( i_pts == -1 && p_stream->fmt.i_cat == VIDEO_ES )
- i_pts = i_interpolated_pts;
+ else if( i_pts == -1 && (p_stream->fmt.i_cat == VIDEO_ES || p_stream->fmt.i_codec == VLC_CODEC_OPUS) )
+ i_pts = i_interpolated_pts; /* FIXME : why is this incorrect for vorbis? */
else if( i_pts == -1 ) i_pts = VLC_TS_INVALID;
if( p_stream->fmt.i_cat == AUDIO_ES )
TAB_APPEND( p_ogg->i_streams, p_ogg->pp_stream, p_stream );
memset( p_stream, 0, sizeof(logical_stream_t) );
- p_stream->p_headers = 0;
- p_stream->i_secondary_header_packets = 0;
-
- p_stream->i_keyframe_offset = 0;
- p_stream->i_skip_frames = 0;
-
- p_stream->i_data_start = 0;
es_format_Init( &p_stream->fmt, 0, 0 );
es_format_Init( &p_stream->fmt_old, 0, 0 );
i_format_tag = GetWLE((oggpacket.packet+124));
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 =
GetDWLE((oggpacket.packet+128));
p_stream->fmt.i_bitrate =
p_buffer[4] = '\0';
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;
es_out_Control( p_demux->out, ES_OUT_SET_ES, p_stream->p_es );
}
- p_ogg->i_bitrate += p_stream->fmt.i_bitrate;
+ if ( p_stream->fmt.i_bitrate == 0 &&
+ ( p_stream->fmt.i_cat == VIDEO_ES ||
+ p_stream->fmt.i_cat == AUDIO_ES ) )
+ p_ogg->b_partial_bitrate = true;
+ else
+ p_ogg->i_bitrate += p_stream->fmt.i_bitrate;
p_stream->i_pcr = p_stream->i_previous_pcr =
p_stream->i_interpolated_pcr = -1;
return !b_compatible;
}
-static void Ogg_ExtractXiphMeta( demux_t *p_demux, const void *p_headers, unsigned i_headers, unsigned i_skip )
+static void Ogg_ExtractXiphMeta( demux_t *p_demux, es_format_t *p_fmt,
+ const void *p_headers, unsigned i_headers, unsigned i_skip )
{
demux_sys_t *p_ogg = p_demux->p_sys;
{
int i_cover_score = 0;
int i_cover_idx = 0;
+ float pf_replay_gain[AUDIO_REPLAY_GAIN_MAX];
+ float pf_replay_peak[AUDIO_REPLAY_GAIN_MAX];
+ for(int i=0; i< AUDIO_REPLAY_GAIN_MAX; i++ )
+ {
+ pf_replay_gain[i] = 0;
+ pf_replay_peak[i] = 0;
+ }
vorbis_ParseComment( &p_ogg->p_meta, (uint8_t*)pp_data[1] + i_skip, pi_size[1] - i_skip,
&p_ogg->i_attachments, &p_ogg->attachments,
&i_cover_score, &i_cover_idx,
- &p_ogg->i_seekpoints, &p_ogg->pp_seekpoints );
+ &p_ogg->i_seekpoints, &p_ogg->pp_seekpoints,
+ &pf_replay_gain, &pf_replay_peak );
if( p_ogg->p_meta != NULL && i_cover_idx < p_ogg->i_attachments )
{
char psz_url[128];
p_ogg->attachments[i_cover_idx]->psz_name );
vlc_meta_Set( p_ogg->p_meta, vlc_meta_ArtworkURL, psz_url );
}
+
+ for ( int i=0; i<AUDIO_REPLAY_GAIN_MAX;i++ )
+ {
+ if ( pf_replay_gain[i] != 0 )
+ {
+ p_fmt->audio_replay_gain.pb_gain[i] = true;
+ p_fmt->audio_replay_gain.pf_gain[i] = pf_replay_gain[i];
+ msg_Dbg( p_demux, "setting replay gain %d to %f", i, pf_replay_gain[i] );
+ }
+ if ( pf_replay_peak[i] != 0 )
+ {
+ p_fmt->audio_replay_gain.pb_peak[i] = true;
+ p_fmt->audio_replay_gain.pf_peak[i] = pf_replay_peak[i];
+ msg_Dbg( p_demux, "setting replay peak %d to %f", i, pf_replay_gain[i] );
+ }
+ }
}
if( p_ogg->i_seekpoints > 1 )
for( unsigned i = 0; i < i_count; i++ )
free( pp_data[i] );
}
-static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8_t *p_headers, int i_headers )
+static void Ogg_ExtractMeta( demux_t *p_demux, es_format_t *p_fmt, const uint8_t *p_headers, int i_headers )
{
demux_sys_t *p_ogg = p_demux->p_sys;
- switch( i_codec )
+ switch( p_fmt->i_codec )
{
/* 3 headers with the 2° one being the comments */
case VLC_CODEC_VORBIS:
case VLC_CODEC_THEORA:
- Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6 );
+ Ogg_ExtractXiphMeta( p_demux, p_fmt, p_headers, i_headers, 1+6 );
break;
case VLC_CODEC_OPUS:
- Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 8 );
+ Ogg_ExtractXiphMeta( p_demux, p_fmt, p_headers, i_headers, 8 );
break;
case VLC_CODEC_SPEEX:
- Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 0 );
+ Ogg_ExtractXiphMeta( p_demux, p_fmt, p_headers, i_headers, 0 );
break;
/* N headers with the 2° one being the comments */
case VLC_CODEC_KATE:
/* 1 byte for header type, 7 bytes for magic, 1 reserved zero byte */
- Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+7+1 );
+ Ogg_ExtractXiphMeta( p_demux, p_fmt, p_headers, i_headers, 1+7+1 );
break;
/* TODO */
case VLC_CODEC_FLAC:
- msg_Warn( p_demux, "Ogg_ExtractMeta does not support %4.4s", (const char*)&i_codec );
+ msg_Warn( p_demux, "Ogg_ExtractMeta does not support %4.4s", (const char*)&p_fmt->i_codec );
break;
/* No meta data */
oggpack_readinit( &opb, p_oggpacket->packet, p_oggpacket->bytes);
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 );
oggpack_adv( &opb, 32 );
oggpack_adv( &opb, 32 ); /* mode */
oggpack_adv( &opb, 32 ); /* mode_bitstream_version */
p_stream->fmt.audio.i_channels = oggpack_read( &opb, 32 );
+ fill_channels_info(&p_stream->fmt.audio);
p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 );
}
oggpack_adv( &opb, 64 );
oggpack_adv( &opb, 8 ); /* version_id */
p_stream->fmt.audio.i_channels = oggpack_read( &opb, 8 );
+ fill_channels_info(&p_stream->fmt.audio);
p_stream->i_pre_skip = oggpack_read( &opb, 16 );
if ( p_demux->p_sys->i_length < 0 )
bs_init( &s, p_oggpacket->packet, p_oggpacket->bytes );
bs_read( &s, 1 );
- if( p_oggpacket->bytes > 0 && bs_read( &s, 7 ) == 0 )
+ if( p_oggpacket->bytes > 0 && bs_read( &s, 7 ) != 0 )
{
- 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_channels = bs_read( &s, 3 ) + 1;
+ msg_Dbg( p_demux, "Invalid FLAC STREAMINFO metadata" );
+ return;
+ }
- msg_Dbg( p_demux, "FLAC header, channels: %i, rate: %i",
- p_stream->fmt.audio.i_channels, (int)p_stream->f_rate );
- }
- else
- {
- msg_Dbg( p_demux, "FLAC STREAMINFO metadata too short" );
- }
+ 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_channels = bs_read( &s, 3 ) + 1;
+ fill_channels_info(&p_stream->fmt.audio);
- /* Fake this as the last metadata block */
- *((uint8_t*)p_oggpacket->packet) |= 0x80;
+ msg_Dbg( p_demux, "FLAC header, channels: %i, rate: %i",
+ p_stream->fmt.audio.i_channels, (int)p_stream->f_rate );
}
else
{
- /* This ain't a STREAMINFO metadata */
- msg_Dbg( p_demux, "Invalid FLAC STREAMINFO metadata" );
+ msg_Dbg( p_demux, "FLAC STREAMINFO metadata too short" );
}
+
+ /* Fake this as the last metadata block */
+ *((uint8_t*)p_oggpacket->packet) |= 0x80;
}
static void Ogg_ReadKateHeader( logical_stream_t *p_stream,