in tensorflow_io/core/kernels/audio_video_flac_kernels.cc [400:530]
void Compute(OpKernelContext* context) override {
const Tensor* input_tensor;
OP_REQUIRES_OK(context, context->input("input", &input_tensor));
const Tensor* rate_tensor;
OP_REQUIRES_OK(context, context->input("rate", &rate_tensor));
const int64 rate = rate_tensor->scalar<int64>()();
const int64 samples = input_tensor->shape().dim_size(0);
const int64 channels = input_tensor->shape().dim_size(1);
int64 bytes_per_sample;
switch (input_tensor->dtype()) {
case DT_UINT8:
bytes_per_sample = 1;
break;
case DT_INT16:
bytes_per_sample = 2;
break;
case DT_INT32:
bytes_per_sample = 3;
break;
default:
OP_REQUIRES(context, false,
errors::InvalidArgument(
"data type ", DataTypeString(input_tensor->dtype()),
" not supported"));
}
std::unique_ptr<FLAC__StreamEncoder, void (*)(FLAC__StreamEncoder*)>
encoder(nullptr, [](FLAC__StreamEncoder* p) {
if (p != nullptr) {
FLAC__stream_encoder_delete(p);
}
});
encoder.reset(FLAC__stream_encoder_new());
FLAC__bool ok;
ok = FLAC__stream_encoder_set_verify(encoder.get(), true);
OP_REQUIRES(context, ok, errors::InvalidArgument("unable to set verify"));
// TODO: compression level could be a input tensor node passed in.
// ok = FLAC__stream_encoder_set_compression_level(encoder.get(), 5);
// OP_REQUIRES(context, ok, errors::InvalidArgument("unable to set
// compression level"));
ok = FLAC__stream_encoder_set_channels(encoder.get(), channels);
OP_REQUIRES(context, ok, errors::InvalidArgument("unable to set channels"));
ok = FLAC__stream_encoder_set_bits_per_sample(encoder.get(),
bytes_per_sample * 8);
OP_REQUIRES(context, ok,
errors::InvalidArgument("unable to set bits per sample"));
ok = FLAC__stream_encoder_set_sample_rate(encoder.get(), rate);
OP_REQUIRES(context, ok, errors::InvalidArgument("unable to set rate"));
ok =
FLAC__stream_encoder_set_total_samples_estimate(encoder.get(), samples);
OP_REQUIRES(
context, ok,
errors::InvalidArgument("unable to set total samples estimate"));
Tensor* output_tensor = nullptr;
OP_REQUIRES_OK(
context, context->allocate_output(0, TensorShape({}), &output_tensor));
tstring& output = output_tensor->scalar<tstring>()();
std::unique_ptr<FlacStreamEncoder> stream_encoder;
stream_encoder.reset(new FlacStreamEncoder(&output));
FLAC__StreamEncoderInitStatus s = FLAC__stream_encoder_init_stream(
encoder.get(), FlacStreamEncoder::WriteCallback,
FlacStreamEncoder::SeekCallback, FlacStreamEncoder::TellCallback,
FlacStreamEncoder::MetadataCallback, stream_encoder.get());
OP_REQUIRES(context, (s == FLAC__STREAM_ENCODER_INIT_STATUS_OK),
errors::InvalidArgument("unable to initialize stream: ", s));
std::unique_ptr<FLAC__int32[]> pcm(
new FLAC__int32[FlacStreamEncoder::kSampleBufferCount * channels]);
int64 count = 0;
while (count < samples) {
int64 chunk = (count + FlacStreamEncoder::kSampleBufferCount < samples)
? (FlacStreamEncoder::kSampleBufferCount)
: (samples - count);
switch (input_tensor->dtype()) {
case DT_UINT8:
// convert to signed by sub 0x80
for (int64 i = 0; i < chunk; i++) {
for (int64 c = 0; c < channels; c++) {
pcm.get()[i * channels + c] =
static_cast<int32>(
input_tensor->flat<uint8>()((count + i) * channels + c)) -
0x80;
}
}
break;
case DT_INT16:
for (int64 i = 0; i < chunk; i++) {
for (int64 c = 0; c < channels; c++) {
pcm.get()[i * channels + c] =
input_tensor->flat<int16>()((count + i) * channels + c);
}
}
break;
case DT_INT32:
// right shift 8 bit as int32 was filled
for (int64 i = 0; i < chunk; i++) {
for (int64 c = 0; c < channels; c++) {
pcm.get()[i * channels + c] =
(input_tensor->flat<int32>()((count + i) * channels + c) >>
8);
}
}
break;
}
ok = FLAC__stream_encoder_process_interleaved(encoder.get(), pcm.get(),
chunk);
OP_REQUIRES(
context, ok,
errors::InvalidArgument("unable to process interleaved stream"));
count += chunk;
}
ok = FLAC__stream_encoder_finish(encoder.get());
OP_REQUIRES(context, ok,
errors::InvalidArgument("unable to finish stream"));
}