📄 seekable_stream_encoder.c
字号:
OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_escape_coding(const OggFLAC__SeekableStreamEncoder *encoder)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
return FLAC__stream_encoder_get_do_escape_coding(encoder->private_->FLAC_stream_encoder);
}
OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const OggFLAC__SeekableStreamEncoder *encoder)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
return FLAC__stream_encoder_get_do_exhaustive_model_search(encoder->private_->FLAC_stream_encoder);
}
OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_min_residual_partition_order(const OggFLAC__SeekableStreamEncoder *encoder)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
return FLAC__stream_encoder_get_min_residual_partition_order(encoder->private_->FLAC_stream_encoder);
}
OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_max_residual_partition_order(const OggFLAC__SeekableStreamEncoder *encoder)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
return FLAC__stream_encoder_get_max_residual_partition_order(encoder->private_->FLAC_stream_encoder);
}
OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const OggFLAC__SeekableStreamEncoder *encoder)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
return FLAC__stream_encoder_get_rice_parameter_search_dist(encoder->private_->FLAC_stream_encoder);
}
OggFLAC_API FLAC__uint64 OggFLAC__seekable_stream_encoder_get_total_samples_estimate(const OggFLAC__SeekableStreamEncoder *encoder)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
return FLAC__stream_encoder_get_total_samples_estimate(encoder->private_->FLAC_stream_encoder);
}
OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_process(OggFLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
if(!FLAC__stream_encoder_process(encoder->private_->FLAC_stream_encoder, buffer, samples)) {
encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR;
return false;
}
else
return true;
}
OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_process_interleaved(OggFLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
if(!FLAC__stream_encoder_process_interleaved(encoder->private_->FLAC_stream_encoder, buffer, samples)) {
encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR;
return false;
}
else
return true;
}
/***********************************************************************
*
* Private class methods
*
***********************************************************************/
void set_defaults_(OggFLAC__SeekableStreamEncoder *encoder)
{
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
FLAC__ASSERT(0 != encoder->protected_);
encoder->private_->seek_callback = 0;
encoder->private_->tell_callback = 0;
encoder->private_->write_callback = 0;
encoder->private_->client_data = 0;
encoder->private_->seek_table = 0;
OggFLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect);
}
FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *unused, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
{
OggFLAC__SeekableStreamEncoder *encoder = (OggFLAC__SeekableStreamEncoder*)client_data;
FLAC__StreamEncoderWriteStatus status;
FLAC__uint64 output_position;
(void)unused; /* silence compiler warning about unused parameter */
FLAC__ASSERT(encoder->private_->FLAC_stream_encoder == unused);
if(encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK)
return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR;
/*
* Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets.
*/
if(samples == 0) {
FLAC__MetadataType type = (buffer[0] & 0x7f);
if(type == FLAC__METADATA_TYPE_STREAMINFO)
encoder->protected_->streaminfo_offset = output_position;
else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0)
encoder->protected_->seektable_offset = output_position;
}
/*
* Mark the current seek point if hit (if audio_offset == 0 that
* means we're still writing metadata and haven't hit the first
* frame yet)
*/
if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) {
const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder->private_->FLAC_stream_encoder);
const FLAC__uint64 frame_first_sample = encoder->private_->samples_written;
const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
FLAC__uint64 test_sample;
unsigned i;
for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) {
test_sample = encoder->private_->seek_table->points[i].sample_number;
if(test_sample > frame_last_sample) {
break;
}
else if(test_sample >= frame_first_sample) {
encoder->private_->seek_table->points[i].sample_number = frame_first_sample;
encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset;
encoder->private_->seek_table->points[i].frame_samples = blocksize;
encoder->private_->first_seekpoint_to_check++;
/* DO NOT: "break;" and here's why:
* The seektable template may contain more than one target
* sample for any given frame; we will keep looping, generating
* duplicate seekpoints for them, and we'll clean it up later,
* just before writing the seektable back to the metadata.
*/
}
else {
encoder->private_->first_seekpoint_to_check++;
}
}
}
status = OggFLAC__ogg_encoder_aspect_write_callback_wrapper(&encoder->protected_->ogg_encoder_aspect, FLAC__stream_encoder_get_total_samples_estimate(encoder->private_->FLAC_stream_encoder), buffer, bytes, samples, current_frame, (OggFLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback, encoder, encoder->private_->client_data);
if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
encoder->private_->samples_written += samples;
}
else
encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
return status;
}
void metadata_callback_(const FLAC__StreamEncoder *unused, const FLAC__StreamMetadata *metadata, void *client_data)
{
OggFLAC__SeekableStreamEncoder *encoder = (OggFLAC__SeekableStreamEncoder*)client_data;
FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
const unsigned min_framesize = metadata->data.stream_info.min_framesize;
const unsigned max_framesize = metadata->data.stream_info.max_framesize;
ogg_page page;
FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
/* We get called by the stream encoder when the encoding process
* has finished so that we can update the STREAMINFO and SEEKTABLE
* blocks.
*/
(void)unused; /* silence compiler warning about unused parameter */
FLAC__ASSERT(encoder->private_->FLAC_stream_encoder == unused);
/*@@@ reopen callback here? The docs currently require user to open files in update mode from the start */
/* All this is based on intimate knowledge of the stream header
* layout, but a change to the header format that would break this
* would also break all streams encoded in the previous format.
*/
/*
* Write STREAMINFO stats
*/
simple_ogg_page__init(&page);
if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
simple_ogg_page__clear(&page);
return; /* state already set */
}
/*
* MD5 signature
*/
{
const unsigned md5_offset =
FLAC__STREAM_METADATA_HEADER_LENGTH +
(
FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
) / 8;
if(md5_offset + 16 > (unsigned)page.body_len) {
encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
simple_ogg_page__clear(&page);
return;
}
memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16);
}
/*
* total samples
*/
{
const unsigned total_samples_byte_offset =
FLAC__STREAM_METADATA_HEADER_LENGTH +
(
FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
- 4
) / 8;
if(total_samples_byte_offset + 5 > (unsigned)page.body_len) {
encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
simple_ogg_page__clear(&page);
return;
}
b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0;
b[0] |= (FLAC__byte)((samples >> 32) & 0x0F);
b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
b[4] = (FLAC__byte)(samples & 0xFF);
memcpy(page.body + total_samples_byte_offset, b, 5);
}
/*
* min/max framesize
*/
{
const unsigned min_framesize_offset =
FLAC__STREAM_METADATA_HEADER_LENGTH +
(
FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
) / 8;
if(min_framesize_offset + 6 > (unsigned)page.body_len) {
encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
simple_ogg_page__clear(&page);
return;
}
b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
b[2] = (FLAC__byte)(min_framesize & 0xFF);
b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
b[5] = (FLAC__byte)(max_framesize & 0xFF);
memcpy(page.body + min_framesize_offset, b, 6);
}
if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
simple_ogg_page__clear(&page);
return; /* state already set */
}
simple_ogg_page__clear(&page);
/*
* Write seektable
*/
if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
unsigned i;
FLAC__byte *p;
FLAC__format_seektable_sort(encoder->private_->seek_table);
FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
simple_ogg_page__init(&page);
if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
simple_ogg_page__clear(&page);
return; /* state already set */
}
if(FLAC__STREAM_METADATA_HEADER_LENGTH + (18*encoder->private_->seek_table->num_points) > (unsigned)page.body_len) {
encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
simple_ogg_page__clear(&page);
return;
}
for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) {
FLAC__uint64 xx;
unsigned x;
xx = encoder->private_->seek_table->points[i].sample_number;
b[7] = (FLAC__byte)xx; xx >>= 8;
b[6] = (FLAC__byte)xx; xx >>= 8;
b[5] = (FLAC__byte)xx; xx >>= 8;
b[4] = (FLAC__byte)xx; xx >>= 8;
b[3] = (FLAC__byte)xx; xx >>= 8;
b[2] = (FLAC__byte)xx; xx >>= 8;
b[1] = (FLAC__byte)xx; xx >>= 8;
b[0] = (FLAC__byte)xx; xx >>= 8;
xx = encoder->private_->seek_table->points[i].stream_offset;
b[15] = (FLAC__byte)xx; xx >>= 8;
b[14] = (FLAC__byte)xx; xx >>= 8;
b[13] = (FLAC__byte)xx; xx >>= 8;
b[12] = (FLAC__byte)xx; xx >>= 8;
b[11] = (FLAC__byte)xx; xx >>= 8;
b[10] = (FLAC__byte)xx; xx >>= 8;
b[9] = (FLAC__byte)xx; xx >>= 8;
b[8] = (FLAC__byte)xx; xx >>= 8;
x = encoder->private_->seek_table->points[i].frame_samples;
b[17] = (FLAC__byte)x; x >>= 8;
b[16] = (FLAC__byte)x; x >>= 8;
if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
simple_ogg_page__clear(&page);
return;
}
memcpy(p, b, 18);
}
if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
simple_ogg_page__clear(&page);
return; /* state already set */
}
simple_ogg_page__clear(&page);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -