Commit 46fe18b2 authored by Denis Charmet's avatar Denis Charmet

Implement basic Opus support in MKV

parent 7b8e0d02
...@@ -386,6 +386,11 @@ static block_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket, ...@@ -386,6 +386,11 @@ static block_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
if(spp>0)spp*=opus_packet_get_samples_per_frame(p_oggpacket->packet,48000); if(spp>0)spp*=opus_packet_get_samples_per_frame(p_oggpacket->packet,48000);
if(spp<120||spp>120*48)return NULL; if(spp<120||spp>120*48)return NULL;
/* Since the information isn't always available at the demux level
* use the packet's sample number */
if(!i_nb_samples)
i_nb_samples = spp;
block_t *p_aout_buffer=decoder_NewAudioBuffer( p_dec, spp ); block_t *p_aout_buffer=decoder_NewAudioBuffer( p_dec, spp );
if ( !p_aout_buffer ) if ( !p_aout_buffer )
{ {
......
...@@ -929,10 +929,22 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_ ...@@ -929,10 +929,22 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
/* now parse until key frame */ /* now parse until key frame */
const int es_types[3] = { VIDEO_ES, AUDIO_ES, SPU_ES }; const int es_types[3] = { VIDEO_ES, AUDIO_ES, SPU_ES };
i_cat = es_types[0]; i_cat = es_types[0];
mtime_t i_seek_preroll = 0;
for( int i = 0; i < 2; i_cat = es_types[++i] ) for( int i = 0; i < 2; i_cat = es_types[++i] )
{ {
for( i_track = 0; i_track < tracks.size(); i_track++ ) for( i_track = 0; i_track < tracks.size(); i_track++ )
{ {
if( tracks[i_track]->i_seek_preroll )
{
bool b_enabled;
if( es_out_Control( sys.demuxer.out,
ES_OUT_GET_ES_STATE,
tracks[i_track]->p_es,
&b_enabled ) == VLC_SUCCESS &&
b_enabled )
i_seek_preroll = __MAX( i_seek_preroll,
tracks[i_track]->i_seek_preroll );
}
if( tracks[i_track]->fmt.i_cat == i_cat ) if( tracks[i_track]->fmt.i_cat == i_cat )
{ {
spoint * seekpoint = new spoint(i_track, i_seek_time, i_seek_position, i_seek_position); spoint * seekpoint = new spoint(i_track, i_seek_time, i_seek_position, i_seek_position);
...@@ -968,7 +980,7 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_ ...@@ -968,7 +980,7 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_date ); es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_date );
return; return;
} }
i_date -= i_seek_preroll;
for(;;) for(;;)
{ {
do do
...@@ -1201,6 +1213,7 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s ...@@ -1201,6 +1213,7 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
*pb_key_picture = true; *pb_key_picture = true;
*pb_discardable_picture = false; *pb_discardable_picture = false;
size_t i_tk; size_t i_tk;
*pi_duration = 0;
for( ;; ) for( ;; )
{ {
...@@ -1407,6 +1420,13 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s ...@@ -1407,6 +1420,13 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
} }
} }
} }
#if LIBMATROSKA_VERSION >= 0x010401
else if( MKV_IS_ID( el, KaxDiscardPadding ) )
{
KaxDiscardPadding &dp = *(KaxDiscardPadding*) el;
*pi_duration -= int64(dp);
}
#endif
break; break;
default: default:
msg_Err( &sys.demuxer, "invalid level = %d", i_level ); msg_Err( &sys.demuxer, "invalid level = %d", i_level );
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
extern "C" { extern "C" {
#include "../vobsub.h" #include "../vobsub.h"
#include "../xiph.h"
} }
#include <vlc_codecs.h> #include <vlc_codecs.h>
...@@ -401,6 +402,21 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m ) ...@@ -401,6 +402,21 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
msg_Dbg( &sys.demuxer, "| | | + Track Overlay=%u", uint32( tovr ) ); msg_Dbg( &sys.demuxer, "| | | + Track Overlay=%u", uint32( tovr ) );
} }
#if LIBMATROSKA_VERSION >= 0x010401
else if( MKV_IS_ID( l, KaxCodecDelay ) )
{
KaxCodecDelay &codecdelay = *(KaxCodecDelay*)l;
tk->i_codec_delay = uint64_t( codecdelay ) / 1000;
msg_Dbg( &sys.demuxer, "| | | + Track Codec Delay =%"PRIu64,
tk->i_codec_delay );
}
else if( MKV_IS_ID( l, KaxSeekPreRoll ) )
{
KaxSeekPreRoll &spr = *(KaxSeekPreRoll*)l;
tk->i_seek_preroll = uint64_t(spr) / 1000;
msg_Dbg( &sys.demuxer, "| | | + Track Seek Preroll =%"PRIu64, tk->i_seek_preroll );
}
#endif
else if( MKV_IS_ID( l, KaxContentEncodings ) ) else if( MKV_IS_ID( l, KaxContentEncodings ) )
{ {
EbmlMaster *cencs = static_cast<EbmlMaster*>(l); EbmlMaster *cencs = static_cast<EbmlMaster*>(l);
...@@ -1477,6 +1493,26 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk ) ...@@ -1477,6 +1493,26 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
p_tk->fmt.i_codec = VLC_CODEC_VORBIS; p_tk->fmt.i_codec = VLC_CODEC_VORBIS;
fill_extra_data( p_tk, 0 ); fill_extra_data( p_tk, 0 );
} }
else if( !strncmp( p_tk->psz_codec, "A_OPUS", 6 ) )
{
p_tk->fmt.i_codec = VLC_CODEC_OPUS;
if( !p_tk->fmt.audio.i_rate )
{
msg_Err( &sys.demuxer,"No sampling rate, defaulting to 48kHz");
p_tk->fmt.audio.i_rate = 48000;
}
const uint8_t tags[16] = {'O','p','u','s','T','a','g','s',
0, 0, 0, 0, 0, 0, 0, 0};
unsigned ps[2] = { p_tk->i_extra_data, 16 };
const void *pkt[2] = { (const void *)p_tk->p_extra_data,
(const void *) tags };
if( xiph_PackHeaders( &p_tk->fmt.i_extra,
&p_tk->fmt.p_extra,
ps, pkt, 2 ) )
msg_Err( &sys.demuxer, "Couldn't pack OPUS headers");
}
else if( !strncmp( p_tk->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) || else if( !strncmp( p_tk->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
!strncmp( p_tk->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) ) !strncmp( p_tk->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
{ {
......
...@@ -499,10 +499,8 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock ...@@ -499,10 +499,8 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
msg_Err( p_demux, "unknown track number" ); msg_Err( p_demux, "unknown track number" );
return; return;
} }
if( i_pts + i_duration < p_sys->i_start_pts && tk->fmt.i_cat == AUDIO_ES )
{ i_pts -= tk->i_codec_delay;
return; /* discard audio packets that shouldn't be rendered */
}
if ( tk->fmt.i_cat != NAV_ES ) if ( tk->fmt.i_cat != NAV_ES )
{ {
...@@ -592,9 +590,10 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock ...@@ -592,9 +590,10 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
{ {
memcpy( p_block->p_buffer, tk->p_compression_data->GetBuffer(), tk->p_compression_data->GetSize() ); memcpy( p_block->p_buffer, tk->p_compression_data->GetBuffer(), tk->p_compression_data->GetSize() );
} }
switch( tk->fmt.i_codec )
if( tk->fmt.i_codec == VLC_CODEC_COOK || {
tk->fmt.i_codec == VLC_CODEC_ATRAC3 ) case VLC_CODEC_COOK:
case VLC_CODEC_ATRAC3:
{ {
handle_real_audio(p_demux, tk, p_block, i_pts); handle_real_audio(p_demux, tk, p_block, i_pts);
block_Release(p_block); block_Release(p_block);
...@@ -602,6 +601,27 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock ...@@ -602,6 +601,27 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
i_pts + ( mtime_t )( tk->i_default_duration / 1000 ): i_pts + ( mtime_t )( tk->i_default_duration / 1000 ):
VLC_TS_INVALID; VLC_TS_INVALID;
continue; continue;
}
case VLC_CODEC_SPU:
if( strcmp( tk->psz_codec, "S_VOBSUB" ) )
p_block->i_length = i_duration * tk-> f_timecodescale *
(double) p_segment->i_timescale / 1000.0;
break;
case VLC_CODEC_OPUS:
if( i_duration > 0 )
{
mtime_t i_length = i_duration * tk-> f_timecodescale *
(double) p_segment->i_timescale / 1000.0;
p_block->i_nb_samples = i_length * tk->fmt.audio.i_rate
/ CLOCK_FREQ;
break;
}
else if( i_duration < 0 )
{
/* Opus uses p_block->i_length to handle discard padding */
p_block->i_length = -1 * i_duration * tk->fmt.audio.i_rate
/ CLOCK_FREQ;
}
} }
if ( tk->fmt.i_cat == NAV_ES ) if ( tk->fmt.i_cat == NAV_ES )
...@@ -643,11 +663,6 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock ...@@ -643,11 +663,6 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
#if 0 #if 0
msg_Dbg( p_demux, "block i_dts: %"PRId64" / i_pts: %"PRId64, p_block->i_dts, p_block->i_pts); msg_Dbg( p_demux, "block i_dts: %"PRId64" / i_pts: %"PRId64, p_block->i_dts, p_block->i_pts);
#endif #endif
if( strcmp( tk->psz_codec, "S_VOBSUB" ) )
{
p_block->i_length = i_duration * tk-> f_timecodescale * (double) p_segment->i_timescale / 1000.0;
}
/* FIXME remove when VLC_TS_INVALID work is done */ /* FIXME remove when VLC_TS_INVALID work is done */
if( i == 0 || p_block->i_dts > VLC_TS_INVALID ) if( i == 0 || p_block->i_dts > VLC_TS_INVALID )
p_block->i_dts += VLC_TS_0; p_block->i_dts += VLC_TS_0;
......
...@@ -188,8 +188,6 @@ public: ...@@ -188,8 +188,6 @@ public:
struct mkv_track_t struct mkv_track_t
{ {
// ~mkv_track_t();
bool b_default; bool b_default;
bool b_enabled; bool b_enabled;
bool b_forced; bool b_forced;
...@@ -237,6 +235,10 @@ struct mkv_track_t ...@@ -237,6 +235,10 @@ struct mkv_track_t
uint32_t i_encoding_scope; uint32_t i_encoding_scope;
KaxContentCompSettings *p_compression_data; KaxContentCompSettings *p_compression_data;
/* Matroska 4 new elements used by Opus */
mtime_t i_seek_preroll;
mtime_t i_codec_delay;
}; };
struct mkv_index_t struct mkv_index_t
......
...@@ -60,7 +60,7 @@ static inline unsigned int xiph_CountHeaders( const void *extra, unsigned int i_ ...@@ -60,7 +60,7 @@ static inline unsigned int xiph_CountHeaders( const void *extra, unsigned int i_
static inline int xiph_SplitHeaders(unsigned packet_size[], void * packet[], unsigned *packet_count, static inline int xiph_SplitHeaders(unsigned packet_size[], void * packet[], unsigned *packet_count,
unsigned extra_size, const void *extra) unsigned extra_size, const void *extra)
{ {
const uint8_t *current = extra; const uint8_t *current = (const uint8_t *)extra;
const uint8_t *end = &current[extra_size]; const uint8_t *end = &current[extra_size];
if (extra_size < 1) if (extra_size < 1)
return VLC_EGENERIC; return VLC_EGENERIC;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment