| /* | |
| * Copyright 2025 The WebRTC project authors. All rights reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "video/corruption_detection/evaluation/utils.h" | |
| #include <cstdint> | |
| #include <cstdio> | |
| #include <span> | |
| #include <string> | |
| #include "absl/strings/string_view.h" | |
| #include "api/video/video_codec_type.h" | |
| #include "api/video_codecs/sdp_video_format.h" | |
| #include "api/video_codecs/video_codec.h" | |
| #include "rtc_base/checks.h" | |
| #include "rtc_base/strings/string_builder.h" | |
| #include "rtc_base/system/file_wrapper.h" | |
| #include "test/testsupport/file_utils.h" | |
| namespace webrtc { | |
| namespace { | |
| constexpr char kFrameHeader[] = "FRAME\n"; | |
| // Reading 40 bytes from the Y4M header should be enough to get the resolution | |
| // and framerate. The header starts with: `YUV4MPEG2 W<WIDTH> H<HEIGTH> | |
| // F<NUMERATOR>:<DENOMINATOR>`. | |
| constexpr int kHeaderBytesToRead = 40; | |
| } // namespace | |
| TempY4mFileCreator::TempY4mFileCreator(int width, int height, int framerate) | |
| : width_(width), | |
| height_(height), | |
| framerate_(framerate), | |
| frame_size_(width * height * 3 / 2), | |
| y4m_filepath_(test::TempFilename(test::OutputPath(), "temp_video")) { | |
| // A file with the given name path should just have been created. | |
| RTC_CHECK_EQ(test::GetFileSize(y4m_filepath_), 0); | |
| } | |
| TempY4mFileCreator::~TempY4mFileCreator() { | |
| RTC_CHECK(test::RemoveFile(y4m_filepath_)); | |
| } | |
| void TempY4mFileCreator::CreateTempY4mFile( | |
| std::span<const uint8_t> file_content) { | |
| RTC_CHECK_EQ(file_content.size() % frame_size_, 0) | |
| << "Content size is not a multiple of frame size. Probably some data is " | |
| "missing."; | |
| FileWrapper video_file = FileWrapper::OpenWriteOnly(y4m_filepath_); | |
| RTC_CHECK(video_file.is_open()); | |
| WriteFileHeader(video_file); | |
| // Write frame content. | |
| int frame_number = file_content.size() / frame_size_; | |
| for (int frame_index = 0; frame_index < frame_number; ++frame_index) { | |
| RTC_CHECK(video_file.Write(kFrameHeader, sizeof(kFrameHeader) - 1)); | |
| RTC_CHECK_LT(frame_size_ * frame_index, file_content.size()); | |
| RTC_CHECK(video_file.Write(file_content.data() + frame_size_ * frame_index, | |
| frame_size_)); | |
| } | |
| RTC_CHECK(video_file.Flush()); | |
| } | |
| void TempY4mFileCreator::WriteFileHeader(FileWrapper& video_file) const { | |
| StringBuilder frame_header; | |
| frame_header << "YUV4MPEG2 W" << width_ << " H" << height_ << " F" | |
| << framerate_ << ":1 C420\n"; | |
| RTC_CHECK(video_file.Write(frame_header.str().c_str(), frame_header.size())); | |
| } | |
| Y4mMetadata ReadMetadataFromY4mHeader(absl::string_view clip_path) { | |
| FILE* file = fopen(std::string(clip_path).c_str(), "r"); | |
| RTC_CHECK(file) << "Could not open " << clip_path; | |
| char header[kHeaderBytesToRead]; | |
| RTC_CHECK(fgets(header, sizeof(header), file) != nullptr) | |
| << "File " << clip_path << " is too small"; | |
| fclose(file); | |
| int fps_numerator; | |
| int fps_denominator; | |
| int width; | |
| int height; | |
| RTC_CHECK_EQ(sscanf(header, "YUV4MPEG2 W%u H%u F%u:%u", &width, &height, | |
| &fps_numerator, &fps_denominator), | |
| 4); | |
| RTC_CHECK_NE(fps_denominator, 0); | |
| return {.width = width, | |
| .height = height, | |
| .framerate = fps_numerator / fps_denominator}; | |
| } | |
| SdpVideoFormat GetSdpVideoFormat(VideoCodecType type) { | |
| switch (type) { | |
| case VideoCodecType::kVideoCodecVP8: | |
| return SdpVideoFormat::VP8(); | |
| case VideoCodecType::kVideoCodecVP9: | |
| return SdpVideoFormat::VP9Profile0(); | |
| case VideoCodecType::kVideoCodecAV1: | |
| return SdpVideoFormat::AV1Profile0(); | |
| case VideoCodecType::kVideoCodecH264: | |
| return SdpVideoFormat::H264(); | |
| default: | |
| RTC_FATAL() << "Codec type " << CodecTypeToPayloadString(type) | |
| << " is not supported."; | |
| } | |
| } | |
| } // namespace webrtc |