| 313 | } |
| 314 | |
| 315 | Status ReadAudioFile(const string& filename, const string& audio_format_id, |
| 316 | int32 samples_per_second, int32 channel_count, |
| 317 | const string& stream, std::vector<float>* output_samples) { |
| 318 | // Create an argument list. |
| 319 | string output_filename = io::GetTempFilename("raw"); |
| 320 | const std::vector<string> args = |
| 321 | FfmpegAudioCommandLine(filename, output_filename, audio_format_id, |
| 322 | samples_per_second, channel_count, stream); |
| 323 | // Unfortunately, it's impossible to differentiate an exec failure due to the |
| 324 | // binary being missing and an error from the binary's execution. Therefore, |
| 325 | // check to see if the binary *should* be available. If not, return an error |
| 326 | // that will be converted into a helpful error message by the TensorFlow op. |
| 327 | if (!IsBinaryInstalled(kFfmpegExecutable)) { |
| 328 | return Status(error::Code::NOT_FOUND, StrCat("FFmpeg could not be found.")); |
| 329 | } |
| 330 | |
| 331 | // Execute ffmpeg and report errors. |
| 332 | pid_t child_pid = ::fork(); |
| 333 | if (child_pid < 0) { |
| 334 | return Status(error::Code::UNKNOWN, |
| 335 | StrCat("fork failed: ", strerror(errno))); |
| 336 | } |
| 337 | if (child_pid == 0) { |
| 338 | ExecuteFfmpeg(args); |
| 339 | } else { |
| 340 | int status_code; |
| 341 | ::waitpid(child_pid, &status_code, 0); |
| 342 | if (status_code) { |
| 343 | return Status(error::Code::UNKNOWN, |
| 344 | StrCat("FFmpeg execution failed: ", status_code)); |
| 345 | } |
| 346 | *output_samples = ReadPcmFile(output_filename); |
| 347 | TF_QCHECK_OK(Env::Default()->DeleteFile(output_filename)) |
| 348 | << output_filename; |
| 349 | return Status::OK(); |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | Status CreateAudioFile(const string& audio_format_id, int32 bits_per_second, |
| 354 | int32 samples_per_second, int32 channel_count, |