+/*****************************************************************************
+ *
+ *****************************************************************************/
+static ts_storage_t *TsStorageNew( const char *psz_tmp_path, int64_t i_tmp_size_max )
+{
+ ts_storage_t *p_storage = calloc( 1, sizeof(ts_storage_t) );
+ if( !p_storage )
+ return NULL;
+
+ /* */
+ p_storage->p_next = NULL;
+
+ /* */
+ p_storage->i_file_max = i_tmp_size_max;
+ p_storage->i_file_size = 0;
+ p_storage->p_filew = GetTmpFile( &p_storage->psz_file, psz_tmp_path );
+ if( p_storage->psz_file )
+ p_storage->p_filer = utf8_fopen( p_storage->psz_file, "rb" );
+
+ /* */
+ p_storage->i_cmd_w = 0;
+ p_storage->i_cmd_r = 0;
+ p_storage->i_cmd_max = 30000;
+ p_storage->p_cmd = malloc( p_storage->i_cmd_max * sizeof(*p_storage->p_cmd) );
+ //fprintf( stderr, "\nSTORAGE name=%s size=%d kbytes\n", p_storage->psz_file, p_storage->i_cmd_max * sizeof(*p_storage->p_cmd) /1024 );
+
+ if( !p_storage->p_cmd || !p_storage->p_filew || !p_storage->p_filer )
+ {
+ TsStorageDelete( p_storage );
+ return NULL;
+ }
+ return p_storage;
+}
+static void TsStorageDelete( ts_storage_t *p_storage )
+{
+ while( p_storage->i_cmd_r < p_storage->i_cmd_w )
+ {
+ ts_cmd_t cmd;
+
+ TsStoragePopCmd( p_storage, &cmd, true );
+
+ CmdClean( &cmd );
+ }
+ free( p_storage->p_cmd );
+
+ if( p_storage->p_filer )
+ fclose( p_storage->p_filer );
+ if( p_storage->p_filew )
+ fclose( p_storage->p_filew );
+
+ if( p_storage->psz_file )
+ {
+ utf8_unlink( p_storage->psz_file );
+ free( p_storage->psz_file );
+ }
+
+ free( p_storage );
+}
+static void TsStoragePack( ts_storage_t *p_storage )
+{
+ /* Try to release a bit of memory */
+ if( p_storage->i_cmd_w >= p_storage->i_cmd_max )
+ return;
+
+ p_storage->i_cmd_max = __MAX( p_storage->i_cmd_w, 1 );
+
+ ts_cmd_t *p_new = realloc( p_storage->p_cmd, p_storage->i_cmd_max * sizeof(*p_storage->p_cmd) );
+ if( p_new )
+ p_storage->p_cmd = p_new;
+}
+static bool TsStorageIsFull( ts_storage_t *p_storage, const ts_cmd_t *p_cmd )
+{
+ if( p_cmd && p_cmd->i_type == C_SEND && p_storage->i_cmd_w > 0 )
+ {
+ size_t i_size = sizeof(*p_cmd->send.p_block) + p_cmd->send.p_block->i_buffer;
+
+ if( p_storage->i_file_size + i_size >= p_storage->i_file_max )
+ return true;
+ }
+ return p_storage->i_cmd_w >= p_storage->i_cmd_max;
+}
+static bool TsStorageIsEmpty( ts_storage_t *p_storage )
+{
+ return !p_storage || p_storage->i_cmd_r >= p_storage->i_cmd_w;
+}
+static void TsStoragePushCmd( ts_storage_t *p_storage, const ts_cmd_t *p_cmd, bool b_flush )
+{
+ ts_cmd_t cmd = *p_cmd;
+
+ assert( !TsStorageIsFull( p_storage, p_cmd ) );
+
+ if( cmd.i_type == C_SEND )
+ {
+ block_t *p_block = cmd.send.p_block;
+
+ cmd.send.p_block = NULL;
+ cmd.send.i_offset = ftell( p_storage->p_filew );
+
+ if( fwrite( p_block, sizeof(*p_block), 1, p_storage->p_filew ) != 1 )
+ {
+ block_Release( p_block );
+ return;
+ }
+ p_storage->i_file_size += sizeof(*p_block);
+ if( p_block->i_buffer > 0 )
+ {
+ if( fwrite( p_block->p_buffer, p_block->i_buffer, 1, p_storage->p_filew ) != 1 )
+ {
+ block_Release( p_block );
+ return;
+ }
+ }
+ p_storage->i_file_size += p_block->i_buffer;
+ block_Release( p_block );
+
+ if( b_flush )
+ fflush( p_storage->p_filew );
+ }
+ p_storage->p_cmd[p_storage->i_cmd_w++] = cmd;
+}
+static void TsStoragePopCmd( ts_storage_t *p_storage, ts_cmd_t *p_cmd, bool b_flush )
+{
+ assert( !TsStorageIsEmpty( p_storage ) );
+
+ *p_cmd = p_storage->p_cmd[p_storage->i_cmd_r++];
+ if( p_cmd->i_type == C_SEND )
+ {
+ block_t block;
+
+ if( !b_flush &&
+ !fseek( p_storage->p_filer, p_cmd->send.i_offset, SEEK_SET ) &&
+ fread( &block, sizeof(block), 1, p_storage->p_filer ) == 1 )
+ {
+ block_t *p_block = block_Alloc( block.i_buffer );
+ if( p_block )
+ {
+ p_block->i_dts = block.i_dts;
+ p_block->i_pts = block.i_pts;
+ p_block->i_flags = block.i_flags;
+ p_block->i_length = block.i_length;
+ p_block->i_rate = block.i_rate;
+ p_block->i_nb_samples = block.i_nb_samples;
+ p_block->i_buffer = fread( p_block->p_buffer, 1, block.i_buffer, p_storage->p_filer );
+ }
+ p_cmd->send.p_block = p_block;
+ }
+ else
+ {
+ //fprintf( stderr, "TsStoragePopCmd: %m\n" );
+ p_cmd->send.p_block = block_Alloc( 1 );
+ }
+ }
+}
+