static void set_16( filter_t *p_filter, void *p_buf, uint16_t i_val ) { if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB ) SetWBE( p_buf, i_val ); else SetWLE( p_buf, i_val ); }
/***************************************************************************** * DoWork: convert a buffer *****************************************************************************/ static block_t *DoWork( filter_t * p_filter, block_t *p_in_buf ) { /* AC3 is natively big endian. Most SPDIF devices have the native * endianness of the computer system. * On Mac OS X however, little endian devices are also common. */ static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 }; static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x01 }; uint16_t i_frame_size = p_in_buf->i_buffer / 2; uint8_t * p_in = p_in_buf->p_buffer; block_t *p_out_buf = filter_NewAudioBuffer( p_filter, AOUT_SPDIF_SIZE ); if( !p_out_buf ) goto out; uint8_t * p_out = p_out_buf->p_buffer; /* Copy the S/PDIF headers. */ if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB ) { vlc_memcpy( p_out, p_sync_be, 6 ); p_out[4] = p_in[5] & 0x7; /* bsmod */ SetWBE( p_out + 6, i_frame_size << 4 ); vlc_memcpy( &p_out[8], p_in, i_frame_size * 2 ); } else { vlc_memcpy( p_out, p_sync_le, 6 ); p_out[5] = p_in[5] & 0x7; /* bsmod */ SetWLE( p_out + 6, i_frame_size << 4 ); swab( p_in, &p_out[8], i_frame_size * 2 ); } vlc_memset( p_out + 8 + i_frame_size * 2, 0, AOUT_SPDIF_SIZE - i_frame_size * 2 - 8 ); p_out_buf->i_dts = p_in_buf->i_dts; p_out_buf->i_pts = p_in_buf->i_pts; p_out_buf->i_nb_samples = p_in_buf->i_nb_samples; p_out_buf->i_buffer = AOUT_SPDIF_SIZE; out: block_Release( p_in_buf ); return p_out_buf; }
/***************************************************************************** * Open: open cdda *****************************************************************************/ static int Open( vlc_object_t *p_this ) { access_t *p_access = (access_t*)p_this; access_sys_t *p_sys; vcddev_t *vcddev; char *psz_name; if( !p_access->psz_filepath || !*p_access->psz_filepath ) { /* Only when selected */ if( !p_access->psz_access || !*p_access->psz_access ) return VLC_EGENERIC; psz_name = var_InheritString( p_this, "cd-audio" ); if( !psz_name ) return VLC_EGENERIC; } else psz_name = ToLocaleDup( p_access->psz_filepath ); #if defined( _WIN32 ) || defined( __OS2__ ) if( psz_name[0] && psz_name[1] == ':' && psz_name[2] == '\\' && psz_name[3] == '\0' ) psz_name[2] = '\0'; #endif /* Open CDDA */ if( (vcddev = ioctl_Open( VLC_OBJECT(p_access), psz_name ) ) == NULL ) { msg_Warn( p_access, "could not open %s", psz_name ); free( psz_name ); return VLC_EGENERIC; } free( psz_name ); /* Set up p_access */ STANDARD_BLOCK_ACCESS_INIT p_sys->vcddev = vcddev; /* Do we play a single track ? */ p_sys->i_track = var_InheritInteger( p_access, "cdda-track" ) - 1; if( p_sys->i_track < 0 ) { /* We only do separate items if the whole disc is requested */ input_thread_t *p_input = access_GetParentInput( p_access ); int i_ret = -1; if( p_input ) { input_item_t *p_current = input_GetItem( p_input ); if( p_current ) i_ret = GetTracks( p_access, p_current ); vlc_object_release( p_input ); } if( i_ret < 0 ) goto error; } else { /* Build a WAV header for the output data */ memset( &p_sys->waveheader, 0, sizeof(WAVEHEADER) ); SetWLE( &p_sys->waveheader.Format, 1 ); /*WAVE_FORMAT_PCM*/ SetWLE( &p_sys->waveheader.BitsPerSample, 16); p_sys->waveheader.MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F'); p_sys->waveheader.Length = 0; /* we just don't know */ p_sys->waveheader.ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E'); p_sys->waveheader.SubChunkID = VLC_FOURCC('f', 'm', 't', ' '); SetDWLE( &p_sys->waveheader.SubChunkLength, 16); SetWLE( &p_sys->waveheader.Modus, 2); SetDWLE( &p_sys->waveheader.SampleFreq, 44100); SetWLE( &p_sys->waveheader.BytesPerSample, 2 /*Modus*/ * 16 /*BitsPerSample*/ / 8 ); SetDWLE( &p_sys->waveheader.BytesPerSec, 2*16/8 /*BytesPerSample*/ * 44100 /*SampleFreq*/ ); p_sys->waveheader.DataChunkID = VLC_FOURCC('d', 'a', 't', 'a'); p_sys->waveheader.DataLength = 0; /* we just don't know */ p_sys->i_first_sector = var_InheritInteger( p_access, "cdda-first-sector" ); p_sys->i_last_sector = var_InheritInteger( p_access, "cdda-last-sector" ); /* Tracknumber in MRL */ if( p_sys->i_first_sector < 0 || p_sys->i_last_sector < 0 ) { const int i_titles = ioctl_GetTracksMap( VLC_OBJECT(p_access), p_sys->vcddev, &p_sys->p_sectors ); if( p_sys->i_track >= i_titles ) { msg_Err( p_access, "invalid track number" ); goto error; } p_sys->i_first_sector = p_sys->p_sectors[p_sys->i_track]; p_sys->i_last_sector = p_sys->p_sectors[p_sys->i_track+1]; } p_sys->i_sector = p_sys->i_first_sector; p_access->info.i_size = (p_sys->i_last_sector - p_sys->i_first_sector) * (int64_t)CDDA_DATA_SIZE; } return VLC_SUCCESS; error: free( p_sys->p_sectors ); ioctl_Close( VLC_OBJECT(p_access), p_sys->vcddev ); free( p_sys ); return VLC_EGENERIC; }
/***************************************************************************** * Open: open a dummy audio device *****************************************************************************/ static int Open( vlc_object_t * p_this ) { aout_instance_t * p_aout = (aout_instance_t *)p_this; char * psz_name, * psz_format; const char * const * ppsz_compare = format_list; int i_channels, i = 0; psz_name = var_CreateGetString( p_this, "audiofile-file" ); if( !psz_name || !*psz_name ) { msg_Err( p_aout, "you need to specify an output file name" ); free( psz_name ); return VLC_EGENERIC; } /* Allocate structure */ p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) ); if( p_aout->output.p_sys == NULL ) return VLC_ENOMEM; if( !strcmp( psz_name, "-" ) ) p_aout->output.p_sys->p_file = stdout; else p_aout->output.p_sys->p_file = utf8_fopen( psz_name, "wb" ); free( psz_name ); if ( p_aout->output.p_sys->p_file == NULL ) { free( p_aout->output.p_sys ); return VLC_EGENERIC; } p_aout->output.pf_play = Play; /* Audio format */ psz_format = var_CreateGetString( p_this, "audiofile-format" ); while ( *ppsz_compare != NULL ) { if ( !strncmp( *ppsz_compare, psz_format, strlen(*ppsz_compare) ) ) { break; } ppsz_compare++; i++; } if ( *ppsz_compare == NULL ) { msg_Err( p_aout, "cannot understand the format string (%s)", psz_format ); if( p_aout->output.p_sys->p_file != stdout ) fclose( p_aout->output.p_sys->p_file ); free( p_aout->output.p_sys ); free( psz_format ); return VLC_EGENERIC; } free( psz_format ); p_aout->output.output.i_format = format_int[i]; if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { p_aout->output.i_nb_samples = A52_FRAME_NB; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; aout_VolumeNoneInit( p_aout ); } else { p_aout->output.i_nb_samples = FRAME_SIZE; aout_VolumeSoftInit( p_aout ); } /* Channels number */ i_channels = var_CreateGetInteger( p_this, "audiofile-channels" ); if( i_channels > 0 && i_channels <= CHANNELS_MAX ) { p_aout->output.output.i_physical_channels = pi_channels_maps[i_channels]; } /* WAV header */ p_aout->output.p_sys->b_add_wav_header = var_CreateGetBool( p_this, "audiofile-wav" ); if( p_aout->output.p_sys->b_add_wav_header ) { /* Write wave header */ WAVEHEADER *wh = &p_aout->output.p_sys->waveh; memset( wh, 0, sizeof(wh) ); switch( p_aout->output.output.i_format ) { case VLC_CODEC_FL32: wh->Format = WAVE_FORMAT_IEEE_FLOAT; wh->BitsPerSample = sizeof(float) * 8; break; case VLC_CODEC_U8: wh->Format = WAVE_FORMAT_PCM; wh->BitsPerSample = 8; break; case VLC_CODEC_S16L: default: wh->Format = WAVE_FORMAT_PCM; wh->BitsPerSample = 16; break; } wh->MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F'); wh->Length = 0; /* temp, to be filled in as we go */ wh->ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E'); wh->SubChunkID = VLC_FOURCC('f', 'm', 't', ' '); wh->SubChunkLength = 16; wh->Modus = aout_FormatNbChannels( &p_aout->output.output ); wh->SampleFreq = p_aout->output.output.i_rate; wh->BytesPerSample = wh->Modus * ( wh->BitsPerSample / 8 ); wh->BytesPerSec = wh->BytesPerSample * wh->SampleFreq; wh->DataChunkID = VLC_FOURCC('d', 'a', 't', 'a'); wh->DataLength = 0; /* temp, to be filled in as we go */ /* Header -> little endian format */ SetWLE( &wh->Format, wh->Format ); SetWLE( &wh->BitsPerSample, wh->BitsPerSample ); SetDWLE( &wh->SubChunkLength, wh->SubChunkLength ); SetWLE( &wh->Modus, wh->Modus ); SetDWLE( &wh->SampleFreq, wh->SampleFreq ); SetWLE( &wh->BytesPerSample, wh->BytesPerSample ); SetDWLE( &wh->BytesPerSec, wh->BytesPerSec ); if( fwrite( wh, sizeof(WAVEHEADER), 1, p_aout->output.p_sys->p_file ) != 1 ) { msg_Err( p_aout, "write error (%m)" ); } } return 0; }
/***************************************************************************** * DoWork: convert a buffer *****************************************************************************/ static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf ) { uint32_t i_ac5_spdif_type = 0; uint16_t i_fz = p_in_buf->i_nb_samples * 4; uint16_t i_frame, i_length = p_in_buf->i_buffer; static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x00, 0x00 }; static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x00 }; if( p_in_buf->i_buffer != p_filter->p_sys->i_frame_size ) { /* Frame size changed, reset everything */ msg_Warn( p_filter, "Frame size changed from %zu to %zu, " "resetting everything.", p_filter->p_sys->i_frame_size, p_in_buf->i_buffer ); p_filter->p_sys->i_frame_size = p_in_buf->i_buffer; p_filter->p_sys->p_buf = xrealloc( p_filter->p_sys->p_buf, p_in_buf->i_buffer * 3 ); p_filter->p_sys->i_frames = 0; } /* Backup frame */ /* TODO: keeping the blocks in a list would save one memcpy */ memcpy( p_filter->p_sys->p_buf + p_in_buf->i_buffer * p_filter->p_sys->i_frames, p_in_buf->p_buffer, p_in_buf->i_buffer ); p_filter->p_sys->i_frames++; if( p_filter->p_sys->i_frames < 3 ) { if( p_filter->p_sys->i_frames == 1 ) /* We'll need the starting date */ p_filter->p_sys->start_date = p_in_buf->i_pts; /* Not enough data */ block_Release( p_in_buf ); return NULL; } p_filter->p_sys->i_frames = 0; block_t *p_out_buf = filter_NewAudioBuffer( p_filter, 12 * p_in_buf->i_nb_samples ); if( !p_out_buf ) goto out; for( i_frame = 0; i_frame < 3; i_frame++ ) { uint16_t i_length_padded = i_length; uint8_t * p_out = p_out_buf->p_buffer + (i_frame * i_fz); uint8_t * p_in = p_filter->p_sys->p_buf + (i_frame * i_length); switch( p_in_buf->i_nb_samples ) { case 512: i_ac5_spdif_type = 0x0B; break; case 1024: i_ac5_spdif_type = 0x0C; break; case 2048: i_ac5_spdif_type = 0x0D; break; } /* Copy the S/PDIF headers. */ if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB ) { memcpy( p_out, p_sync_be, 6 ); p_out[5] = i_ac5_spdif_type; SetWBE( p_out + 6, i_length << 3 ); } else { memcpy( p_out, p_sync_le, 6 ); p_out[4] = i_ac5_spdif_type; SetWLE( p_out + 6, i_length << 3 ); } if( ( (p_in[0] == 0x1F || p_in[0] == 0x7F) && p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFL ) || ( (p_in[0] == 0xFF || p_in[0] == 0xFE) && p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB ) ) { /* We are dealing with a big endian bitstream and a little endian output * or a little endian bitstream and a big endian output. * Byteswap the stream */ swab( p_in, p_out + 8, i_length ); /* If i_length is odd, we have to adjust swapping a bit.. */ if( i_length & 1 ) { p_out[8+i_length-1] = 0; p_out[8+i_length] = p_in[i_length-1]; i_length_padded++; } } else { memcpy( p_out + 8, p_in, i_length ); } if( i_fz > i_length + 8 ) { memset( p_out + 8 + i_length_padded, 0, i_fz - i_length_padded - 8 ); } } p_out_buf->i_pts = p_filter->p_sys->start_date; p_out_buf->i_nb_samples = p_in_buf->i_nb_samples * 3; p_out_buf->i_buffer = p_out_buf->i_nb_samples * 4; out: block_Release( p_in_buf ); return p_out_buf; }