Status GetNextInternal()

in tensorflow_compression/cc/kernels/y4m_dataset_kernels.cc [117:213]


      Status GetNextInternal(IteratorContext* ctx,
                             vector<Tensor>* out_tensors,
                             bool* end_of_sequence) override {
        mutex_lock l(mu_);

        do {
          if (file_) {
            const string_view frame_header = "FRAME\n";
            size_t frame_size = width_ * height_ * 3;
            int64_t cbcr_width = width_;
            int64_t cbcr_height = height_;
            string_view frame_buffer;

            if (chroma_format_ == ChromaFormat::I420) {
              frame_size /= 2;
              cbcr_width /= 2;
              cbcr_height /= 2;
            }
            const size_t cbcr_size = cbcr_width * cbcr_height;

            // This is a no-op for the second and subsequent frames.
            buffer_.resize(frame_header.size() + frame_size);

            // Try to read the next frame.
            Status status = file_->Read(file_pos_, buffer_.size(),
                                        &frame_buffer, &buffer_[0]);

            // Yield frame on successful read of a complete frame.
            if (status.ok()) {
              DCHECK_EQ(frame_buffer.size(), buffer_.size());

              if (!absl::ConsumePrefix(&frame_buffer, frame_header)) {
                return errors::InvalidArgument(
                    "Input file '", dataset()->filenames_[file_index_],
                    "' has a FRAME marker at byte ", file_pos_, " which is "
                    "either invalid or has unsupported frame parameters.");
              }

              Tensor y_tensor(ctx->allocator({}), DT_UINT8,
                              {height_, width_, 1});
              Tensor cbcr_tensor(ctx->allocator({}), DT_UINT8,
                                 {cbcr_height, cbcr_width, 2});
              auto flat_y = y_tensor.flat<uint8_t>();
              auto flat_cbcr = cbcr_tensor.flat<uint8_t>();
              std::memcpy(flat_y.data(), frame_buffer.data(), flat_y.size());
              frame_buffer.remove_prefix(flat_y.size());
              for (int i = 0; i < cbcr_size; i++) {
                flat_cbcr.data()[2*i] = frame_buffer[i];
                flat_cbcr.data()[2*i+1] = frame_buffer[cbcr_size+i];
              }
              out_tensors->push_back(std::move(y_tensor));
              out_tensors->push_back(std::move(cbcr_tensor));

              file_pos_ += buffer_.size();
              *end_of_sequence = false;
              return status;
            }

            // Catch any other errors than out of range, which needs special
            // treatment.
            if (!errors::IsOutOfRange(status)) {
              return status;
            }

            // If frame buffer is not empty, we just read an incomplete frame
            // (or one that has frame parameters that change its size).
            if (!frame_buffer.empty()) {
              return errors::InvalidArgument(
                  "Input file '", dataset()->filenames_[file_index_],
                  "' has an incomplete or unsupported frame at byte ",
                  file_pos_, ". Expected to read ", buffer_.size(),
                  " bytes, only ", frame_buffer.size(), " were available.");
            }

            // Out of range error with empty frame buffer means correct end of
            // file. Clean up and check for next file.
            file_.reset();
            ++file_index_;
          }

          // Exit if there are no more files to process.
          if (file_index_ >= dataset()->filenames_.size()) {
            *end_of_sequence = true;
            return Status::OK();
          }

          // Open next file.
          TF_RETURN_IF_ERROR(ctx->env()->NewRandomAccessFile(
              dataset()->filenames_[file_index_], &file_));

          // Read and parse header.
          TF_RETURN_IF_ERROR(ReadHeader(*file_, file_index_, buffer_));
          TF_RETURN_IF_ERROR(ParseHeader(buffer_, file_index_, width_, height_,
                                         chroma_format_));
          file_pos_ = buffer_.size();
        } while (true);
      }