[vlc-devel] Adding Cook support in mkv - needs review
Denis Charmet
typx at dinauz.org
Wed Jul 4 00:27:27 CEST 2012
Hi,
I've been trying to add COOK support in the MKV demux. My only sample
coming from #3410 can be played correctly with this patch but I have to
admit that my total lack of knowledge of the codec makes me fear it's not
enough, especially since seeking in a cook track is broken.
For now I have similar results with vlc's and avformat's demuxes, but
I'd like some reviews before I formally submit it.
If you have samples I'm also interested.
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..583c40a 100644
--- a/modules/demux/mkv/matroska_segment.cpp
+++ b/modules/demux/mkv/matroska_segment.cpp
@@ -22,12 +22,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
+#include <arpa/inet.h>
#include "matroska_segment.hpp"
-
#include "chapters.hpp"
-
#include "demux.hpp"
-
+#include "util.hpp"
#include "Ebml_parser.hpp"
extern "C" {
@@ -87,6 +86,7 @@ matroska_segment_c::~matroska_segment_c()
{
delete tracks[i_track]->p_compression_data;
es_format_Clean( &tracks[i_track]->fmt );
+ free( tracks[i_track]->p_subpackets);
free( tracks[i_track]->p_extra_data );
free( tracks[i_track]->psz_codec );
delete tracks[i_track];
@@ -696,6 +696,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 +1289,42 @@ 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 = htons(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) htons(priv->version);
+ p_tk->i_sub_packet_h = (uint32_t) htons(priv->sub_packet_h);
+ p_tk->i_frame_size = (uint32_t) htons(priv->frame_size);
+ p_tk->i_subpacket_size = (uint32_t) htons(priv->sub_packet_size);
+ p_tk->i_subpackets = p_tk->i_sub_packet_h * p_tk->i_frame_size / p_tk->i_subpacket_size;
+ p_tk->p_subpackets = (block_t**) calloc( p_tk->i_subpackets, sizeof(block_t*));
+ p_tk->i_subpacket = 0;
+
+ if( version == 4 )
+ {
+ real_audio_private_v4 * v4 = (real_audio_private_v4*) priv;
+ p_tk->fmt.audio.i_channels = htons(v4->channels);
+ p_tk->fmt.audio.i_bitspersample = htons(v4->sample_size);
+ p_tk->fmt.audio.i_rate = htons(v4->sample_rate);
+ }
+ else if( version == 5 )
+ {
+ real_audio_private_v5 * v5 = (real_audio_private_v5*) priv;
+ p_tk->fmt.audio.i_channels = htons(v5->channels);
+ p_tk->fmt.audio.i_bitspersample = htons(v5->sample_size);
+ p_tk->fmt.audio.i_rate = htons(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..9fe4e77 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,6 +621,7 @@ 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 ) );
}
}
+ if( tk->fmt.i_cat == VIDEO_ES || tk->fmt.i_cat == AUDIO_ES )
tk->i_last_dts = p_block->i_dts;
#if 0
@@ -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..a481d7a 100644
--- a/modules/demux/mkv/mkv.hpp
+++ b/modules/demux/mkv/mkv.hpp
@@ -202,6 +202,14 @@ struct mkv_track_t
/* audio */
unsigned int i_original_rate;
+ /* real audio */
+ uint32_t i_sub_packet_h;
+ uint32_t i_frame_size;
+ uint32_t i_subpacket_size;
+ block_t **p_subpackets;
+ size_t i_subpackets;
+ size_t i_subpacket;
+
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..5c9c745 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,84 @@ 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;
+ size_t size = p_blk->i_buffer;
+
+ if( p_tk->i_last_dts == VLC_TS_INVALID )
+ {
+ for( size_t i = 0; i < p_tk->i_subpackets; i++)
+ if( p_tk->p_subpackets[i] )
+ {
+ block_Release(p_tk->p_subpackets[i]);
+ p_tk->p_subpackets[i] = NULL;
+ }
+ p_tk->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_tk->i_frame_size / p_tk->i_subpacket_size;
+ const int y = p_tk->i_subpacket / ( p_tk->i_frame_size / p_tk->i_subpacket_size );
+
+ for( int i = 0; i < i_num; i++ )
+ {
+ int i_index = p_tk->i_sub_packet_h * i +
+ ((p_tk->i_sub_packet_h + 1) / 2) * (y&1) + (y>>1);
+ if( i_index >= p_tk->i_subpackets )
+ return;
+
+ block_t *p_block = block_New( p_demux, p_tk->i_subpacket_size );
+ if( !p_block )
+ return;
+
+ if( size < p_tk->i_subpacket_size )
+ return;
+
+ memcpy( p_block->p_buffer, p_frame, p_tk->i_subpacket_size );
+ p_block->i_dts = VLC_TS_INVALID;
+ p_block->i_pts = VLC_TS_INVALID;
+ if( !p_tk->i_subpacket )
+ {
+ p_tk->i_last_dts =
+ p_block->i_pts = i_pts + VLC_TS_0;
+ }
+
+ p_frame += p_tk->i_subpacket_size;
+ size -= p_tk->i_subpacket_size;
+
+ p_tk->i_subpacket++;
+ p_tk->p_subpackets[i_index] = p_block;
+ }
+ }
+ else
+ {
+ /*TODO*/
+ }
+ if( p_tk->i_subpacket == p_tk->i_subpackets )
+ {
+ for( size_t i = 0; i < p_tk->i_subpackets; i++)
+ {
+ es_out_Send( p_demux->out, p_tk->p_es, p_tk->p_subpackets[i]);
+ p_tk->p_subpackets[i] = NULL;
+ }
+ p_tk->i_subpacket = 0;
+ }
+}
diff --git a/modules/demux/mkv/util.hpp b/modules/demux/mkv/util.hpp
index ba03eaa..d6231f1 100644
--- a/modules/demux/mkv/util.hpp
+++ b/modules/demux/mkv/util.hpp
@@ -26,3 +26,46 @@
#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;
+};
+
+
More information about the vlc-devel
mailing list