File: y4m_frame_reader.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (113 lines) | stat: -rw-r--r-- 3,828 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 *  Copyright (c) 2018 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 <stdio.h>

#include <charconv>
#include <string>

#include "api/scoped_refptr.h"
#include "api/video/i420_buffer.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "rtc_base/logging.h"
#include "rtc_base/string_encode.h"
#include "rtc_base/strings/string_builder.h"
#include "test/testsupport/file_utils.h"
#include "test/testsupport/frame_reader.h"

namespace webrtc {
namespace test {
namespace {
constexpr int kFrameHeaderSize = 6;  // "FRAME\n"
}  // namespace

void ParseY4mHeader(std::string filepath,
                    Resolution* resolution,
                    int* header_size) {
  FILE* file = fopen(filepath.c_str(), "r");
  RTC_CHECK(file != nullptr) << "Cannot open " << filepath;

  // Length of Y4M header is technically unlimited due to the comment tag 'X'.
  char h[1024];
  RTC_CHECK(fgets(h, sizeof(h), file) != nullptr)
      << "File " << filepath << " is too small";
  fclose(file);

  std::vector<absl::string_view> header = split(h, ' ');
  RTC_CHECK(!header.empty() && header[0] == "YUV4MPEG2")
      << filepath << " is not a valid Y4M file";

  for (size_t i = 1; i < header.size(); ++i) {
    RTC_CHECK(!header[i].empty());
    switch (header[i][0]) {
      case 'W': {
        auto n = header[i].substr(1);
        std::from_chars(n.data(), n.data() + n.size(), resolution->width);
        continue;
      }
      case 'H': {
        auto n = header[i].substr(1);
        std::from_chars(n.data(), n.data() + n.size(), resolution->height);
        continue;
      }
      default: {
        continue;
      }
    }
  }

  RTC_CHECK_GT(resolution->width, 0) << "Width must be positive";
  RTC_CHECK_GT(resolution->height, 0) << "Height must be positive";

  *header_size = strcspn(h, "\n") + 1;
  RTC_CHECK(static_cast<unsigned>(*header_size) < sizeof(h))
      << filepath << " has unexpectedly large header";
}

Y4mFrameReaderImpl::Y4mFrameReaderImpl(std::string filepath,
                                       RepeatMode repeat_mode)
    : YuvFrameReaderImpl(filepath, Resolution(), repeat_mode) {}

void Y4mFrameReaderImpl::Init() {
  file_ = fopen(filepath_.c_str(), "rb");
  RTC_CHECK(file_ != nullptr) << "Cannot open " << filepath_;

  ParseY4mHeader(filepath_, &resolution_, &header_size_bytes_);
  frame_size_bytes_ =
      CalcBufferSize(VideoType::kI420, resolution_.width, resolution_.height);
  frame_size_bytes_ += kFrameHeaderSize;

  size_t file_size_bytes = GetFileSize(filepath_);
  RTC_CHECK_GT(file_size_bytes, 0u) << "File " << filepath_ << " is empty";
  RTC_CHECK_GT(file_size_bytes, header_size_bytes_)
      << "File " << filepath_ << " is too small";

  num_frames_ = static_cast<int>((file_size_bytes - header_size_bytes_) /
                                 frame_size_bytes_);
  RTC_CHECK_GT(num_frames_, 0u) << "File " << filepath_ << " is too small";
  header_size_bytes_ += kFrameHeaderSize;
}

std::unique_ptr<FrameReader> CreateY4mFrameReader(std::string filepath) {
  return CreateY4mFrameReader(filepath,
                              YuvFrameReaderImpl::RepeatMode::kSingle);
}

std::unique_ptr<FrameReader> CreateY4mFrameReader(
    std::string filepath,
    YuvFrameReaderImpl::RepeatMode repeat_mode) {
  Y4mFrameReaderImpl* frame_reader =
      new Y4mFrameReaderImpl(filepath, repeat_mode);
  frame_reader->Init();
  return std::unique_ptr<FrameReader>(frame_reader);
}

}  // namespace test
}  // namespace webrtc