+static const uint8_t * MetaRead( demux_t *p_demux, const uint8_t *p_peek )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ int i_len;
+ char *psz;
+
+ /* Title */
+ i_len = *p_peek ; p_peek++;
+ if( i_len > 0 )
+ {
+ psz = malloc( i_len + 1 );
+ memcpy( psz, p_peek, i_len );
+ psz[i_len] = '\0';
+
+ EnsureUTF8( psz );
+ msg_Dbg( p_demux, " - title=`%s'", psz );
+ p_sys->psz_title = psz;
+ }
+ p_peek += i_len;
+
+ /* Authors */
+ i_len = *p_peek ; p_peek++;
+ if( i_len > 0 )
+ {
+ psz = malloc( i_len + 1 );
+ memcpy( psz, p_peek, i_len );
+ psz[i_len] = '\0';
+
+ EnsureUTF8( psz );
+ msg_Dbg( p_demux, " - artist=`%s'", psz );
+ p_sys->psz_artist = psz;
+ }
+ p_peek += i_len;
+
+ /* Copyright */
+ i_len = *p_peek ; p_peek++;
+ if( i_len > 0 )
+ {
+ psz = malloc( i_len + 1 );
+ memcpy( psz, p_peek, i_len );
+ psz[i_len] = '\0';
+
+ EnsureUTF8( psz );
+ msg_Dbg( p_demux, " - Copyright=`%s'", psz );
+ p_sys->psz_copyright = psz;
+ }
+ p_peek += i_len;
+
+ /* Comment */
+ i_len = *p_peek ; p_peek++;
+ if( i_len > 0 )
+ {
+ psz = malloc( i_len + 1 );
+ memcpy( psz, p_peek, i_len );
+ psz[i_len] = '\0';
+
+ EnsureUTF8( psz );
+ msg_Dbg( p_demux, " - Comment=`%s'", psz );
+ p_sys->psz_description = psz;
+ }
+ p_peek += i_len;
+
+ return p_peek;
+}
+
+
+static int ReadCodecSpecificData( demux_t *p_demux, int i_len, int i_num )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ es_format_t fmt;
+ real_track_t *tk;
+ const uint8_t *p_peek;
+
+ msg_Dbg( p_demux, " - specific data len=%d", i_len );
+ if( stream_Peek(p_demux->s, &p_peek, i_len) < i_len ) return VLC_EGENERIC;
+
+ if( ( i_len >= 8 ) && !memcmp( &p_peek[4], "VIDO", 4 ) )
+ {
+ es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( p_peek[8], p_peek[9],
+ p_peek[10], p_peek[11] ) );
+ fmt.video.i_width = GetWBE( &p_peek[12] );
+ fmt.video.i_height= GetWBE( &p_peek[14] );
+
+ fmt.i_extra = 8;
+ fmt.p_extra = malloc( 8 );
+ ((uint32_t*)fmt.p_extra)[0] = GetDWBE( &p_peek[26] );
+ ((uint32_t*)fmt.p_extra)[1] = GetDWBE( &p_peek[30] );
+
+ msg_Dbg( p_demux, " - video 0x%08x 0x%08x",
+ ((uint32_t*)fmt.p_extra)[0], ((uint32_t*)fmt.p_extra)[1] );
+
+ if( GetDWBE( &p_peek[30] ) == 0x10003000 ||
+ GetDWBE( &p_peek[30] ) == 0x10003001 )
+ {
+ fmt.i_codec = VLC_FOURCC( 'R','V','1','3' );
+ }
+ else if( GetDWBE( &p_peek[30] ) == 0x20001000 ||
+ GetDWBE( &p_peek[30] ) == 0x20100001 ||
+ GetDWBE( &p_peek[30] ) == 0x20200002 )
+ {
+ fmt.i_codec = VLC_FOURCC( 'R','V','2','0' );
+ }
+ else if( GetDWBE( &p_peek[30] ) == 0x30202002 )
+ {
+ fmt.i_codec = VLC_FOURCC( 'R','V','3','0' );
+ }
+ else if( GetDWBE( &p_peek[30] ) == 0x40000000 )
+ {
+ fmt.i_codec = VLC_FOURCC( 'R','V','4','0' );
+ }
+
+ msg_Dbg( p_demux, " - video %4.4s %dx%d",
+ (char*)&fmt.i_codec, fmt.video.i_width, fmt.video.i_height );
+
+ tk = malloc( sizeof( real_track_t ) );
+ tk->i_out_subpacket = 0;
+ tk->i_subpacket = 0;
+ tk->i_subpackets = 0;
+ tk->p_subpackets = NULL;
+ tk->p_subpackets_timecode = NULL;
+ tk->i_id = i_num;
+ tk->fmt = fmt;
+ tk->i_frame = 0;
+ tk->p_frame = NULL;
+ tk->p_es = es_out_Add( p_demux->out, &fmt );
+
+ TAB_APPEND( p_sys->i_track, p_sys->track, tk );
+ }
+ else if( !strncmp( (char *)p_peek, ".ra\xfd", 4 ) )
+ {
+ int i_header_size = 0;
+ int i_flavor = 0;
+ int i_coded_frame_size = 0;
+ int i_subpacket_h = 0;
+ int i_frame_size = 0;
+ int i_subpacket_size = 0;
+ char p_genr[4];
+ int i_version = GetWBE( &p_peek[4] ); /* [0..3] = '.','r','a',0xfd */
+ msg_Dbg( p_demux, " - audio version=%d", i_version );
+
+ p_peek += 6; /* 4 + version */
+ es_format_Init( &fmt, AUDIO_ES, 0 );
+
+ if( i_version == 3 ) /* RMF version 3 or .ra version 3 */
+ {
+ i_header_size = GetWBE( p_peek ); p_peek += 2; /* Size from now */
+ p_peek += 10; /* Unknown */
+
+ msg_Dbg( p_demux, "Data Size: %i", GetDWBE( p_peek ) );
+ p_peek += 4; /* Data Size */
+
+ /* Meta Datas */
+ p_peek = MetaRead( p_demux, p_peek );
+
+ p_peek ++; /* Unknown */
+ p_peek ++; /* FourCC length = 4 */
+ memcpy( (char *)&fmt.i_codec, p_peek, 4 ); p_peek += 4; /* FourCC*/
+
+ fmt.audio.i_channels = 1; /* This is always the case in rm3 */
+ fmt.audio.i_rate = 8000;
+
+ msg_Dbg( p_demux, " - audio codec=%4.4s channels=%d rate=%dHz",
+ (char*)&fmt.i_codec, fmt.audio.i_channels, fmt.audio.i_rate );
+ }
+ else /* RMF version 4/5 or .ra version 4 */
+ {
+ p_peek += 2; /* 00 00 */
+ p_peek += 4; /* .ra4 or .ra5 */
+ p_peek += 4; /* data size */
+ p_peek += 2; /* version (4 or 5) */
+ i_header_size = GetDWBE( p_peek ); p_peek += 4; /* header size */
+ i_flavor = GetWBE( p_peek ); p_peek += 2; /* codec flavor */
+ i_coded_frame_size = GetDWBE( p_peek ); p_peek += 4; /* coded frame size*/
+ p_peek += 4; /* ?? */
+ p_peek += 4; /* ?? */
+ p_peek += 4; /* ?? */
+ i_subpacket_h = GetWBE( p_peek ); p_peek += 2; /* 1 */
+ i_frame_size = GetWBE( p_peek ); p_peek += 2; /* frame size */
+ i_subpacket_size = GetWBE( p_peek ); p_peek += 2; /* subpacket_size */
+ if( (!i_subpacket_size && !p_sys->b_is_real_audio )
+ || !i_frame_size || !i_coded_frame_size )
+ return VLC_EGENERIC;
+ p_peek += 2; /* ?? */
+
+ if( i_version == 5 ) p_peek += 6; /* 0, srate, 0 */
+
+ fmt.audio.i_rate = GetWBE( p_peek ); p_peek += 2; /* Sample Rate */
+ p_peek += 2; /* ?? */
+ fmt.audio.i_bitspersample = GetWBE( p_peek ); p_peek += 2;/* Sure?*/
+ fmt.audio.i_channels = GetWBE( p_peek ); p_peek += 2; /* Channels */
+ fmt.audio.i_blockalign = i_frame_size;
+
+ if( i_version == 5 )
+ {
+ memcpy( (char *)p_genr, p_peek, 4 ); p_peek += 4; /* genr */
+ memcpy( (char *)&fmt.i_codec, p_peek, 4 ); p_peek += 4;
+ }
+ else /* version 4 */
+ {
+ p_peek += 1 + p_peek[0]; /* Inteleaver ID string and lenth */
+ memcpy( (char *)&fmt.i_codec, p_peek + 1, 4 ); /* FourCC */
+ p_peek += 1 + p_peek[0];
+ }
+
+ msg_Dbg( p_demux, " - audio codec=%4.4s channels=%d rate=%dHz",
+ (char*)&fmt.i_codec, fmt.audio.i_channels, fmt.audio.i_rate );
+
+ p_peek += 3; /* ?? */
+
+ if( p_sys->b_is_real_audio )
+ {
+ p_peek = MetaRead( p_demux, p_peek );
+ }
+ else
+ {
+ if( i_version == 5 ) p_peek++;
+ /* Extra Data then: DWord + byte[] */
+ fmt.i_extra = GetDWBE( p_peek ); p_peek += 4;
+ }
+ }
+
+ switch( fmt.i_codec )
+ {
+ case VLC_FOURCC('l','p','c','J'):
+ fmt.i_codec = VLC_FOURCC( '1','4','_','4' );
+ case VLC_FOURCC('1','4','_','4'):
+ fmt.audio.i_blockalign = 0x14 ;
+ break;
+
+ case VLC_FOURCC('2','8','_','8'):
+ fmt.i_extra = 0;
+ fmt.audio.i_blockalign = i_coded_frame_size;
+ break;
+
+ case VLC_FOURCC( 'd','n','e','t' ):
+ fmt.i_codec = VLC_FOURCC( 'a','5','2',' ' );
+ break;
+
+ case VLC_FOURCC( 'r','a','a','c' ):
+ case VLC_FOURCC( 'r','a','c','p' ):
+ fmt.i_codec = VLC_FOURCC( 'm','p','4','a' );
+
+ if( fmt.i_extra > 0 ) { fmt.i_extra--; p_peek++; }
+ if( fmt.i_extra > 0 )
+ {
+ fmt.p_extra = malloc( fmt.i_extra );
+ if( fmt.p_extra == NULL )
+ {
+ msg_Err( p_demux, "Error in the extra data" );
+ return VLC_EGENERIC;
+ }
+ memcpy( fmt.p_extra, p_peek, fmt.i_extra );
+ }
+ break;
+
+ case VLC_FOURCC('s','i','p','r'):
+ fmt.audio.i_flavor = i_flavor;
+ case VLC_FOURCC('c','o','o','k'):
+ case VLC_FOURCC('a','t','r','c'):
+ if( !memcmp( p_genr, "genr", 4 ) )
+ fmt.audio.i_blockalign = i_subpacket_size;
+ else
+ fmt.audio.i_blockalign = i_coded_frame_size;
+
+ if( fmt.i_extra > 0 )
+ {
+ fmt.p_extra = malloc( fmt.i_extra );
+ if( fmt.p_extra == NULL )
+ {
+ msg_Err( p_demux, "Error in the extra data" );
+ return VLC_EGENERIC;
+ }
+ memcpy( fmt.p_extra, p_peek, fmt.i_extra );
+ }
+ break;
+
+ case VLC_FOURCC('r','a','l','f'):
+ msg_Dbg( p_demux, " - audio codec not supported=%4.4s",
+ (char*)&fmt.i_codec );
+ break;
+
+ default:
+ msg_Dbg( p_demux, " - unknown audio codec=%4.4s",
+ (char*)&fmt.i_codec );
+ break;
+ }
+
+ if( fmt.i_codec != 0 )
+ {
+ msg_Dbg( p_demux, " - extra data=%d", fmt.i_extra );
+
+ tk = malloc( sizeof( real_track_t ) );
+ tk->i_id = i_num;
+ tk->fmt = fmt;
+ tk->i_frame = 0;
+ tk->p_frame = NULL;
+
+ tk->i_subpacket_h = i_subpacket_h;
+ tk->i_subpacket_size = i_subpacket_size;
+ tk->i_coded_frame_size = i_coded_frame_size;
+ tk->i_frame_size = i_frame_size;
+
+ tk->i_out_subpacket = 0;
+ tk->i_subpacket = 0;
+ tk->i_subpackets = 0;
+ tk->p_subpackets = NULL;
+ tk->p_subpackets_timecode = NULL;
+ if( fmt.i_codec == VLC_FOURCC('c','o','o','k')
+ || fmt.i_codec == VLC_FOURCC('a','t','r','c') )
+ {
+ tk->i_subpackets =
+ i_subpacket_h * i_frame_size / tk->i_subpacket_size;
+ tk->p_subpackets =
+ calloc( tk->i_subpackets, sizeof(block_t *) );
+ tk->p_subpackets_timecode =
+ calloc( tk->i_subpackets , sizeof( int64_t ) );
+ }
+ else if( fmt.i_codec == VLC_FOURCC('2','8','_','8') )
+ {
+ tk->i_subpackets =
+ i_subpacket_h * i_frame_size / tk->i_coded_frame_size;
+ tk->p_subpackets =
+ calloc( tk->i_subpackets, sizeof(block_t *) );
+ tk->p_subpackets_timecode =
+ calloc( tk->i_subpackets , sizeof( int64_t ) );
+ }
+
+ /* Check if the calloc went correctly */
+ if( tk->p_subpackets == NULL )
+ {
+ tk->i_subpackets = 0;
+ msg_Err( p_demux, "Can't alloc subpacket" );
+ return VLC_EGENERIC;
+ }
+
+ tk->p_es = es_out_Add( p_demux->out, &fmt );
+
+ TAB_APPEND( p_sys->i_track, p_sys->track, tk );
+ }
+ }
+
+ return VLC_SUCCESS;
+}