Commit 59e5b9a5 authored by Denis Charmet's avatar Denis Charmet Committed by Jean-Baptiste Kempf

Adding Cook support in mkv

Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 4d7dd6cf
......@@ -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);
}
......
......@@ -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 )
......
......@@ -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;
......
......@@ -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 );
}
......@@ -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;
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment