[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