[vlc-devel] Adding Cook support in mkv - needs review
Denis Charmet
typx at dinauz.org
Fri Jul 20 00:01:54 CEST 2012
Hi,
Here's an updated patch if you have more remarks...
Regards,
--
TypX
Le mauvais esprit est un art de vivre
---
diff --git a/modules/demux/mkv/matroska_segment.cpp b/modules/demux/mkv/matroska_segment.cpp
index 199b2c5..581e0ea 100644
--- a/modules/demux/mkv/matroska_segment.cpp
+++ b/modules/demux/mkv/matroska_segment.cpp
@@ -23,11 +23,9 @@
*****************************************************************************/
#include "matroska_segment.hpp"
-
#include "chapters.hpp"
-
#include "demux.hpp"
-
+#include "util.hpp"
#include "Ebml_parser.hpp"
extern "C" {
@@ -87,6 +85,7 @@ matroska_segment_c::~matroska_segment_c()
{
delete tracks[i_track]->p_compression_data;
es_format_Clean( &tracks[i_track]->fmt );
+ delete tracks[i_track]->p_sys;
free( tracks[i_track]->p_extra_data );
free( tracks[i_track]->psz_codec );
delete tracks[i_track];
@@ -696,6 +695,9 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
int i_cat;
bool b_has_key = false;
+ for( size_t i = 0; i < tracks.size(); i++)
+ tracks[i]->i_last_dts = VLC_TS_INVALID;
+
if( i_global_position >= 0 )
{
/* Special case for seeking in files with no cues */
@@ -1286,14 +1288,45 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
msg_Err( &sys.demuxer, "Invalid Real ExtraData 0x%4.4s", (char *)p );
p_tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
}
- else {
+ else
+ {
+ real_audio_private * priv = (real_audio_private*) p_tk->p_extra_data;
if( !strcmp( p_tk->psz_codec, "A_REAL/COOK" ) )
+ {
p_tk->fmt.i_codec = VLC_CODEC_COOK;
+ p_tk->fmt.audio.i_blockalign = hton16(priv->sub_packet_size);
+ }
else if( !strcmp( p_tk->psz_codec, "A_REAL/ATRC" ) )
p_tk->fmt.i_codec = VLC_CODEC_ATRAC3;
else if( !strcmp( p_tk->psz_codec, "A_REAL/28_8" ) )
p_tk->fmt.i_codec = VLC_CODEC_RA_288;
/* FIXME RALF and SIPR */
+ uint16_t version = (uint16_t) hton16(priv->version);
+ p_tk->p_sys =
+ new Cook_PrivateTrackData( hton16(priv->sub_packet_h),
+ hton16(priv->frame_size),
+ hton16(priv->sub_packet_size));
+ if( unlikely( !p_tk->p_sys ) )
+ continue;
+
+ if( unlikely( p_tk->p_sys->Init() ) )
+ continue;
+
+ if( version == 4 )
+ {
+ real_audio_private_v4 * v4 = (real_audio_private_v4*) priv;
+ p_tk->fmt.audio.i_channels = hton16(v4->channels);
+ p_tk->fmt.audio.i_bitspersample = hton16(v4->sample_size);
+ p_tk->fmt.audio.i_rate = hton16(v4->sample_rate);
+ }
+ else if( version == 5 )
+ {
+ real_audio_private_v5 * v5 = (real_audio_private_v5*) priv;
+ p_tk->fmt.audio.i_channels = hton16(v5->channels);
+ p_tk->fmt.audio.i_bitspersample = hton16(v5->sample_size);
+ p_tk->fmt.audio.i_rate = hton16(v5->sample_rate);
+ }
+ msg_Dbg(&sys.demuxer, "%d channels %d bits %d Hz",p_tk->fmt.audio.i_channels, p_tk->fmt.audio.i_bitspersample, p_tk->fmt.audio.i_rate);
fill_extra_data( p_tk, p_tk->fmt.i_codec == VLC_CODEC_RA_288 ? 0 : 78);
}
diff --git a/modules/demux/mkv/mkv.cpp b/modules/demux/mkv/mkv.cpp
index f71e960..1bd4a4f 100644
--- a/modules/demux/mkv/mkv.cpp
+++ b/modules/demux/mkv/mkv.cpp
@@ -468,20 +468,6 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, virtual_ch
p_vsegment->Seek( *p_demux, i_date, i_time_offset, p_chapter, i_global_position );
}
-/* Utility function for BlockDecode */
-static block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset)
-{
- if( unlikely( i_mem > SIZE_MAX - offset ) )
- return NULL;
-
- block_t *p_block = block_New( p_demux, i_mem + offset );
- if( likely(p_block != NULL) )
- {
- memcpy( p_block->p_buffer + offset, p_mem, i_mem );
- }
- return p_block;
-}
-
/* Needed by matroska_segment::Seek() and Seek */
void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock,
mtime_t i_pts, mtime_t i_duration, bool f_mandatory )
@@ -591,6 +577,17 @@ 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() );
}
+ if( tk->fmt.i_codec == VLC_CODEC_COOK ||
+ tk->fmt.i_codec == VLC_CODEC_ATRAC3 )
+ {
+ handle_real_audio(p_demux, tk, p_block, i_pts);
+ block_Release(p_block);
+ i_pts = ( tk->i_default_duration )?
+ i_pts + ( mtime_t )( tk->i_default_duration / 1000 ):
+ VLC_TS_INVALID;
+ continue;
+ }
+
if ( tk->fmt.i_cat == NAV_ES )
{
// TODO handle the start/stop times of this packet
@@ -624,7 +621,8 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
p_block->i_dts = min( i_pts, tk->i_last_dts + ( mtime_t )( tk->i_default_duration / 1000 ) );
}
}
- tk->i_last_dts = p_block->i_dts;
+ if( tk->fmt.i_cat == VIDEO_ES || tk->fmt.i_cat == AUDIO_ES )
+ tk->i_last_dts = p_block->i_dts;
#if 0
msg_Dbg( p_demux, "block i_dts: %"PRId64" / i_pts: %"PRId64, p_block->i_dts, p_block->i_pts);
@@ -719,11 +717,16 @@ static int Demux( demux_t *p_demux)
else
p_sys->i_pts = p_sys->i_chapter_time + ( block->GlobalTimecode() / (mtime_t) 1000 );
- /* The blocks are in coding order so we can safely consider that only references are in chronological order */
- if( p_sys->i_pts > p_sys->i_pcr + 300000 )
+ mtime_t i_pcr = VLC_TS_INVALID;
+ for( size_t i = 0; i < p_segment->tracks.size(); i++)
+ if( p_segment->tracks[i]->i_last_dts > VLC_TS_INVALID &&
+ ( p_segment->tracks[i]->i_last_dts < i_pcr || i_pcr == VLC_TS_INVALID ))
+ i_pcr = p_segment->tracks[i]->i_last_dts;
+
+ if( i_pcr > p_sys->i_pcr + 300000 )
{
es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr );
- p_sys->i_pcr = p_sys->i_pts;
+ p_sys->i_pcr = i_pcr;
}
if( p_sys->i_pts >= p_sys->i_start_pts )
diff --git a/modules/demux/mkv/mkv.hpp b/modules/demux/mkv/mkv.hpp
index 1f8c1b4..0751a88 100644
--- a/modules/demux/mkv/mkv.hpp
+++ b/modules/demux/mkv/mkv.hpp
@@ -174,6 +174,13 @@ struct matroska_stream_c
/*****************************************************************************
* definitions of structures and functions used by this plugins
*****************************************************************************/
+class PrivateTrackData
+{
+public:
+ virtual ~PrivateTrackData() {}
+ virtual int32_t Init() { return 0; }
+};
+
struct mkv_track_t
{
// ~mkv_track_t();
@@ -202,6 +209,9 @@ struct mkv_track_t
/* audio */
unsigned int i_original_rate;
+ /* Private track paramters */
+ PrivateTrackData *p_sys;
+
bool b_inited;
/* data to be send first */
int i_data_init;
diff --git a/modules/demux/mkv/util.cpp b/modules/demux/mkv/util.cpp
index 8ce1cb7..dbe63b4 100644
--- a/modules/demux/mkv/util.cpp
+++ b/modules/demux/mkv/util.cpp
@@ -21,9 +21,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
-
#include "util.hpp"
+#include "demux.hpp"
+#include <stdint.h>
/*****************************************************************************
* Local prototypes
*****************************************************************************/
@@ -78,4 +79,108 @@ block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
}
#endif
+/* Utility function for BlockDecode */
+block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset)
+{
+ if( unlikely( i_mem > SIZE_MAX - offset ) )
+ return NULL;
+
+ block_t *p_block = block_New( p_demux, i_mem + offset );
+ if( likely(p_block != NULL) )
+ {
+ memcpy( p_block->p_buffer + offset, p_mem, i_mem );
+ }
+ return p_block;
+}
+
+
+void handle_real_audio(demux_t * p_demux, mkv_track_t * p_tk, block_t * p_blk, mtime_t i_pts)
+{
+ uint8_t * p_frame = p_blk->p_buffer;
+ Cook_PrivateTrackData * p_sys = (Cook_PrivateTrackData *) p_tk->p_sys;
+ size_t size = p_blk->i_buffer;
+
+ if( p_tk->i_last_dts == VLC_TS_INVALID )
+ {
+ for( size_t i = 0; i < p_sys->i_subpackets; i++)
+ if( p_sys->p_subpackets[i] )
+ {
+ block_Release(p_sys->p_subpackets[i]);
+ p_sys->p_subpackets[i] = NULL;
+ }
+ p_sys->i_subpacket = 0;
+ }
+
+ if( p_tk->fmt.i_codec == VLC_CODEC_COOK ||
+ p_tk->fmt.i_codec == VLC_CODEC_ATRAC3 )
+ {
+ const uint32_t i_num = p_sys->i_frame_size / p_sys->i_subpacket_size;
+ const int y = p_sys->i_subpacket / ( p_sys->i_frame_size / p_sys->i_subpacket_size );
+
+ for( int i = 0; i < i_num; i++ )
+ {
+ int i_index = p_sys->i_sub_packet_h * i +
+ ((p_sys->i_sub_packet_h + 1) / 2) * (y&1) + (y>>1);
+ if( i_index >= p_sys->i_subpackets )
+ return;
+
+ block_t *p_block = block_New( p_demux, p_sys->i_subpacket_size );
+ if( !p_block )
+ return;
+
+ if( size < p_sys->i_subpacket_size )
+ return;
+
+ memcpy( p_block->p_buffer, p_frame, p_sys->i_subpacket_size );
+ p_block->i_dts = VLC_TS_INVALID;
+ p_block->i_pts = VLC_TS_INVALID;
+ if( !p_sys->i_subpacket )
+ {
+ p_tk->i_last_dts =
+ p_block->i_pts = i_pts + VLC_TS_0;
+ }
+ p_frame += p_sys->i_subpacket_size;
+ size -= p_sys->i_subpacket_size;
+
+ p_sys->i_subpacket++;
+ p_sys->p_subpackets[i_index] = p_block;
+ }
+ }
+ else
+ {
+ /*TODO*/
+ }
+ if( p_sys->i_subpacket == p_sys->i_subpackets )
+ {
+ for( size_t i = 0; i < p_sys->i_subpackets; i++)
+ {
+ es_out_Send( p_demux->out, p_tk->p_es, p_sys->p_subpackets[i]);
+ p_sys->p_subpackets[i] = NULL;
+ }
+ p_sys->i_subpacket = 0;
+ }
+}
+
+int32_t Cook_PrivateTrackData::Init()
+{
+ i_subpackets = (size_t) i_sub_packet_h * (size_t) i_frame_size / (size_t) i_subpacket_size;
+ p_subpackets = (block_t**) calloc(i_subpackets, sizeof(block_t*));
+
+ if( unlikely( !p_subpackets ) )
+ {
+ i_subpackets = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+Cook_PrivateTrackData::~Cook_PrivateTrackData()
+{
+ for( size_t i = 0; i < i_subpackets; i++ )
+ if( p_subpackets[i] )
+ block_Release( p_subpackets[i] );
+
+ free( p_subpackets );
+}
diff --git a/modules/demux/mkv/util.hpp b/modules/demux/mkv/util.hpp
index ba03eaa..738dc5e 100644
--- a/modules/demux/mkv/util.hpp
+++ b/modules/demux/mkv/util.hpp
@@ -26,3 +26,61 @@
#include "mkv.hpp"
block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block );
+
+block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset);
+void handle_real_audio(demux_t * p_demux, mkv_track_t * p_tk, block_t * p_blk, mtime_t i_pts);
+
+
+struct real_audio_private
+{
+ uint32_t fourcc;
+ uint16_t version;
+ uint16_t unknown1;
+ uint8_t unknown2[12];
+ uint16_t unknown3;
+ uint16_t flavor;
+ uint32_t coded_frame_size;
+ uint32_t unknown4[3];
+ uint16_t sub_packet_h;
+ uint16_t frame_size;
+ uint16_t sub_packet_size;
+ uint16_t unknown5;
+};
+
+struct real_audio_private_v4
+{
+ real_audio_private header;
+ uint16_t sample_rate;
+ uint16_t unknown;
+ uint16_t sample_size;
+ uint16_t channels;
+};
+
+
+struct real_audio_private_v5
+{
+ real_audio_private header;
+ uint32_t unknown1;
+ uint16_t unknown2;
+ uint16_t sample_rate;
+ uint16_t unknown3;
+ uint16_t sample_size;
+ uint16_t channels;
+};
+
+class Cook_PrivateTrackData : public PrivateTrackData
+{
+public:
+ Cook_PrivateTrackData(uint16_t sph, uint16_t fs, uint16_t sps):
+ i_sub_packet_h(sph), i_frame_size(fs), i_subpacket_size(sps),
+ p_subpackets(NULL), i_subpackets(0), i_subpacket(0){}
+ ~Cook_PrivateTrackData();
+ int32_t Init();
+
+ uint16_t i_sub_packet_h;
+ uint16_t i_frame_size;
+ uint16_t i_subpacket_size;
+ block_t **p_subpackets;
+ size_t i_subpackets;
+ size_t i_subpacket;
+};
More information about the vlc-devel
mailing list