From 54615321798d53c350d5bc843f37427dd193eb14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Yhuel?= <fyhuel@viotech.net>
Date: Wed, 30 Nov 2011 10:30:52 +0100
Subject: [PATCH] demux/mp4: add parsing of mfra atom

mfra atom contains two leaf atoms, 'tfra' and 'mfro'. The first one
provides file offsets of the chunks in a isml file.

mfra atom support will not help Smooth Streaming support in VLC (at
least for the client part), but can be useful for other
purposes, e.g. to enable VLC to play a "raw" isml file.
---
 modules/demux/mp4/libmp4.c |  155 ++++++++++++++++++++++++++++++++++++++++++++
 modules/demux/mp4/libmp4.h |   33 +++++++++
 2 files changed, 188 insertions(+), 0 deletions(-)

diff --git a/modules/demux/mp4/libmp4.c b/modules/demux/mp4/libmp4.c
index aa83ac0..9b64e37 100644
--- a/modules/demux/mp4/libmp4.c
+++ b/modules/demux/mp4/libmp4.c
@@ -2796,6 +2796,158 @@ static void MP4_FreeBox_sdtp( MP4_Box_t *p_box )
     FREENULL( p_box->data.p_sdtp->p_sample_table );
 }
 
+static int MP4_ReadBox_mfro( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_mfro_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_mfro );
+    MP4_GET4BYTES( p_box->data.p_mfro->i_size );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream,
+             "read box: \"mfro\" size: %"PRIu32"",
+             p_box->data.p_mfro->i_size);
+#endif
+
+    MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_tfra( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    uint32_t i_number_of_entries;
+    MP4_READBOX_ENTER( MP4_Box_data_tfra_t );
+    MP4_Box_data_tfra_t *p_tfra = p_box->data.p_tfra;
+    MP4_GETVERSIONFLAGS( p_box->data.p_tfra );
+
+    MP4_GET4BYTES( p_tfra->i_track_ID );
+    uint32_t i_lengths = 0;
+    MP4_GET4BYTES( i_lengths );
+    MP4_GET4BYTES( p_tfra->i_number_of_entries );
+    i_number_of_entries = p_tfra->i_number_of_entries;
+    p_tfra->i_length_size_of_traf_num = i_lengths >> 4;
+    p_tfra->i_length_size_of_trun_num = ( i_lengths & 0x0c ) >> 2;
+    p_tfra->i_length_size_of_sample_num = i_lengths & 0x03;
+
+    size_t size = 4 + 4*p_tfra->i_version; /* size in {4, 8} */
+    p_tfra->p_time = calloc( i_number_of_entries, size );
+    p_tfra->p_moof_offset = calloc( i_number_of_entries, size );
+
+    size = 1 + p_tfra->i_length_size_of_traf_num; /* size in [|1, 4|] */
+    p_tfra->p_traf_number = calloc( i_number_of_entries, size );
+    size = 1 + p_tfra->i_length_size_of_trun_num;
+    p_tfra->p_trun_number = calloc( i_number_of_entries, size );
+    size = 1 + p_tfra->i_length_size_of_sample_num;
+    p_tfra->p_sample_number = calloc( i_number_of_entries, size );
+
+    if( !p_tfra->p_time || !p_tfra->p_moof_offset || !p_tfra->p_traf_number
+                        || !p_tfra->p_trun_number || !p_tfra->p_sample_number )
+        goto error;
+
+    for( uint32_t i=0; i < i_number_of_entries; i++ )
+    {
+        if( p_tfra->i_version == 1 )
+        {
+            MP4_GET8BYTES( p_tfra->p_time[i*2] );
+            MP4_GET8BYTES( p_tfra->p_moof_offset[i*2] );
+        }
+        else
+        {
+            MP4_GET4BYTES( p_tfra->p_time[i] );
+            MP4_GET4BYTES( p_tfra->p_moof_offset[i] );
+        }
+        switch (p_tfra->i_length_size_of_traf_num)
+        {
+            case 0:
+                MP4_GET1BYTE( p_tfra->p_traf_number[i] );
+                break;
+            case 1:
+                MP4_GET2BYTES( p_tfra->p_traf_number[i*2] );
+                break;
+            case 2:
+                MP4_GET3BYTES( p_tfra->p_traf_number[i*3] );
+                break;
+            case 3:
+                MP4_GET4BYTES( p_tfra->p_traf_number[i*4] );
+                break;
+            default:
+                goto error;
+        }
+
+        switch (p_tfra->i_length_size_of_trun_num)
+        {
+            case 0:
+                MP4_GET1BYTE( p_tfra->p_trun_number[i] );
+                break;
+            case 1:
+                MP4_GET2BYTES( p_tfra->p_trun_number[i*2] );
+                break;
+            case 2:
+                MP4_GET3BYTES( p_tfra->p_trun_number[i*3] );
+                break;
+            case 3:
+                MP4_GET4BYTES( p_tfra->p_trun_number[i*4] );
+                break;
+            default:
+                goto error;
+        }
+
+        switch (p_tfra->i_length_size_of_sample_num)
+        {
+            case 0:
+                MP4_GET1BYTE( p_tfra->p_sample_number[i] );
+                break;
+            case 1:
+                MP4_GET2BYTES( p_tfra->p_sample_number[i*2] );
+                break;
+            case 2:
+                MP4_GET3BYTES( p_tfra->p_sample_number[i*3] );
+                break;
+            case 3:
+                MP4_GET4BYTES( p_tfra->p_sample_number[i*4] );
+                break;
+            default:
+                goto error;
+        }
+    }
+
+#ifdef MP4_VERBOSE
+    if( p_tfra->i_version == 0 )
+    {
+        msg_Dbg( p_stream, "time[0]: %"PRIu32", moof_offset[0]: %"PRIx32"",
+                         p_tfra->p_time[0], p_tfra->p_moof_offset[0] );
+
+        msg_Dbg( p_stream, "time[1]: %"PRIu32", moof_offset[1]: %"PRIx32"",
+                         p_tfra->p_time[1], p_tfra->p_moof_offset[1] );
+    }
+    else
+    {
+        msg_Dbg( p_stream, "time[0]: %"PRIu64", moof_offset[0]: %"PRIx64"",
+                ((uint64_t *)(p_tfra->p_time))[0],
+                ((uint64_t *)(p_tfra->p_moof_offset))[0] );
+
+        msg_Dbg( p_stream, "time[1]: %"PRIu64", moof_offset[1]: %"PRIx64"",
+                ((uint64_t *)(p_tfra->p_time))[1],
+                ((uint64_t *)(p_tfra->p_moof_offset))[1] );
+    }
+
+    msg_Info( p_stream, "number_of_entries is %"PRIu32"", i_number_of_entries );
+    msg_Info( p_stream, "track ID is: %"PRIu32"", p_tfra->i_track_ID );
+#endif
+
+    MP4_READBOX_EXIT( 1 );
+error:
+    MP4_READBOX_EXIT( 0 );
+}
+
+static void MP4_FreeBox_tfra( MP4_Box_t *p_box )
+{
+    FREENULL( p_box->data.p_tfra->p_time );
+    FREENULL( p_box->data.p_tfra->p_moof_offset );
+    FREENULL( p_box->data.p_tfra->p_traf_number );
+    FREENULL( p_box->data.p_tfra->p_trun_number );
+    FREENULL( p_box->data.p_tfra->p_sample_number );
+}
+
 
 /* For generic */
 static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
@@ -3059,12 +3211,15 @@ static const struct
 
     /* found in smoothstreaming */
     { ATOM_traf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
+    { ATOM_mfra,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
     { ATOM_mfhd,    MP4_ReadBox_mfhd,         MP4_FreeBox_Common },
     { ATOM_tfhd,    MP4_ReadBox_tfhd,         MP4_FreeBox_Common },
     { ATOM_trun,    MP4_ReadBox_trun,         MP4_FreeBox_trun },
     { ATOM_trex,    MP4_ReadBox_trex,         MP4_FreeBox_Common },
     { ATOM_mehd,    MP4_ReadBox_mehd,         MP4_FreeBox_Common },
     { ATOM_sdtp,    MP4_ReadBox_sdtp,         MP4_FreeBox_sdtp },
+    { ATOM_tfra,    MP4_ReadBox_tfra,         MP4_FreeBox_tfra },
+    { ATOM_mfro,    MP4_ReadBox_mfro,         MP4_FreeBox_Common },
 
     /* Last entry */
     { 0,              MP4_ReadBox_default,      NULL }
diff --git a/modules/demux/mp4/libmp4.h b/modules/demux/mp4/libmp4.h
index aa016fe..99c81c9 100644
--- a/modules/demux/mp4/libmp4.h
+++ b/modules/demux/mp4/libmp4.h
@@ -83,6 +83,9 @@
 #define ATOM_cprt VLC_FOURCC( 'c', 'p', 'r', 't' )
 #define ATOM_iods VLC_FOURCC( 'i', 'o', 'd', 's' )
 #define ATOM_pasp VLC_FOURCC( 'p', 'a', 's', 'p' )
+#define ATOM_mfra VLC_FOURCC( 'm', 'f', 'r', 'a' )
+#define ATOM_mfro VLC_FOURCC( 'm', 'f', 'r', 'o' )
+#define ATOM_tfra VLC_FOURCC( 't', 'f', 'r', 'a' )
 
 #define ATOM_nmhd VLC_FOURCC( 'n', 'm', 'h', 'd' )
 #define ATOM_mp2v VLC_FOURCC( 'm', 'p', '2', 'v' )
@@ -1018,6 +1021,33 @@ typedef struct
     uint8_t *p_sample_table;
 } MP4_Box_data_sdtp_t;
 
+typedef struct
+{
+    uint8_t  i_version;
+    uint32_t i_flags;
+
+    uint32_t i_size;
+} MP4_Box_data_mfro_t;
+
+typedef struct
+{
+    uint8_t  i_version;
+    uint32_t i_flags;
+
+    uint32_t i_track_ID;
+    uint32_t i_number_of_entries;
+
+    uint8_t i_length_size_of_traf_num;
+    uint8_t i_length_size_of_trun_num;
+    uint8_t i_length_size_of_sample_num;
+
+    uint32_t *p_time;
+    uint32_t *p_moof_offset;
+    uint8_t *p_traf_number;
+    uint8_t *p_trun_number;
+    uint8_t *p_sample_number;
+} MP4_Box_data_tfra_t;
+
 /*
 typedef struct MP4_Box_data__s
 {
@@ -1064,6 +1094,9 @@ typedef union MP4_Box_data_s
     MP4_Box_data_mehd_t *p_mehd;
     MP4_Box_data_sdtp_t *p_sdtp;
 
+    MP4_Box_data_tfra_t *p_tfra;
+    MP4_Box_data_mfro_t *p_mfro;
+
     MP4_Box_data_stsz_t *p_stsz;
     MP4_Box_data_stz2_t *p_stz2;
     MP4_Box_data_stsc_t *p_stsc;
-- 
1.7.4.1

