[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