| 398 | } |
| 399 | |
| 400 | int64_t GetUSBCamera::PNGWriteCallback::process(const std::shared_ptr<io::BaseStream>& stream) { |
| 401 | std::lock_guard<std::mutex> lock(*png_write_mtx_); |
| 402 | logger_->log_info("Writing %d bytes of raw capture data to PNG output", frame_->data_bytes); |
| 403 | png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
| 404 | |
| 405 | if (!png) { |
| 406 | logger_->log_error("Failed to create PNG write struct"); |
| 407 | return 0; |
| 408 | } |
| 409 | |
| 410 | png_infop info = png_create_info_struct(png); |
| 411 | |
| 412 | if (!info) { |
| 413 | logger_->log_error("Failed to create PNG info struct"); |
| 414 | return 0; |
| 415 | } |
| 416 | |
| 417 | if (setjmp(png_jmpbuf(png))) { |
| 418 | logger_->log_error("Failed to set PNG jmpbuf"); |
| 419 | return 0; |
| 420 | } |
| 421 | |
| 422 | try { |
| 423 | |
| 424 | png_set_write_fn(png, this, [](png_structp out_png, |
| 425 | png_bytep out_data, |
| 426 | png_size_t num_bytes) { |
| 427 | auto this_callback = reinterpret_cast<PNGWriteCallback *>(png_get_io_ptr(out_png)); |
| 428 | std::copy(out_data, out_data + num_bytes, std::back_inserter(this_callback->png_output_buf_)); |
| 429 | }, |
| 430 | [](png_structp flush_png) {}); |
| 431 | |
| 432 | png_set_IHDR(png, info, width_, height_, 8, |
| 433 | PNG_COLOR_TYPE_RGB, |
| 434 | PNG_INTERLACE_NONE, |
| 435 | PNG_COMPRESSION_TYPE_DEFAULT, |
| 436 | PNG_FILTER_TYPE_DEFAULT); |
| 437 | png_write_info(png, info); |
| 438 | |
| 439 | png_bytep row_pointers[height_]; |
| 440 | |
| 441 | for (uint32_t y = 0; y < height_; y++) { |
| 442 | row_pointers[y] = reinterpret_cast<png_byte *>(frame_->data) + width_ * y * 3; |
| 443 | } |
| 444 | |
| 445 | png_write_image(png, &row_pointers[0]); |
| 446 | png_write_end(png, nullptr); |
| 447 | |
| 448 | png_destroy_write_struct(&png, &info); |
| 449 | } catch (...) { |
| 450 | if (png && info) { |
| 451 | png_destroy_write_struct(&png, &info); |
| 452 | } |
| 453 | throw; |
| 454 | } |
| 455 | |
| 456 | return stream->write(png_output_buf_.data(), png_output_buf_.size()); |
| 457 | } |