Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(517)

Side by Side Diff: webrtc/modules/video_coding/utility/ivf_file_writer.cc

Issue 1853813002: Add support for writing raw encoder output to .ivf files. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Cleanup Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
12
13 #include "webrtc/base/checks.h"
14 #include "webrtc/base/logging.h"
15 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
16
17 namespace webrtc {
18
19 IvfFileWriter::IvfFileWriter(const char* file_name, FILE* file)
20 : num_frames_(0), file_name_(file_name), file_(file) {
21 RTC_CHECK(file != nullptr);
22 }
23
24 IvfFileWriter::~IvfFileWriter() {
25 Close();
26 }
27
28 const int kResolutionOffset = 12;
29 const int kFrameCountOffset = 24;
30 const size_t kIvfHeaderSize = 32;
31
32 bool IvfFileWriter::SeekTo(size_t offset) {
33 int err = fseek(file_, offset, SEEK_SET);
34 RTC_DCHECK_EQ(0, err);
35 return err == 0;
36 }
37
38 std::unique_ptr<IvfFileWriter> IvfFileWriter::Open(const char* file_name,
39 VideoCodecType codec_type) {
40 std::unique_ptr<IvfFileWriter> file_writer;
41
42 FILE* file = fopen(file_name, "wb");
43 if (file == nullptr) {
44 LOG(LS_ERROR) << "Unable to open IVF file " << file_name
45 << " for binary output.";
46 return file_writer;
47 }
48
49 uint8_t ivf_header[kIvfHeaderSize] = {0};
50 ivf_header[0] = 'D';
51 ivf_header[1] = 'K';
52 ivf_header[2] = 'I';
53 ivf_header[3] = 'F';
54 ByteWriter<uint16_t>::WriteLittleEndian(&ivf_header[4], 0); // Verison.
55 ByteWriter<uint16_t>::WriteLittleEndian(&ivf_header[6], 32); // Header size.
56
57 switch (codec_type) {
58 case kVideoCodecVP8:
59 ivf_header[8] = 'V';
60 ivf_header[9] = 'P';
61 ivf_header[10] = '8';
62 ivf_header[11] = '0';
63 break;
64 case kVideoCodecVP9:
65 ivf_header[8] = 'V';
66 ivf_header[9] = 'P';
67 ivf_header[10] = '9';
68 ivf_header[11] = '0';
69 break;
70 case kVideoCodecH264:
71 ivf_header[8] = 'H';
72 ivf_header[9] = '2';
73 ivf_header[10] = '6';
74 ivf_header[11] = '4';
75 break;
76 default:
77 LOG(LS_ERROR) << "Unknown CODEC type: " << codec_type;
78 return file_writer;
79 }
80
81 // Width and Height (populated on first frame).
82 ByteWriter<uint16_t>::WriteLittleEndian(&ivf_header[12], 0);
83 ByteWriter<uint16_t>::WriteLittleEndian(&ivf_header[14], 0);
84 // Timestamps in milliseconds => time scale of 1/1000.
85 ByteWriter<uint32_t>::WriteLittleEndian(&ivf_header[16], 1000);
86 ByteWriter<uint32_t>::WriteLittleEndian(&ivf_header[20], 1);
87 // Number of frames (populated on close).
88 ByteWriter<uint32_t>::WriteLittleEndian(&ivf_header[24], 0);
89 ByteWriter<uint32_t>::WriteLittleEndian(&ivf_header[28], 0); // Reserved.
90
91 if (fwrite(ivf_header, sizeof(uint8_t), kIvfHeaderSize, file) !=
92 kIvfHeaderSize) {
93 LOG(LS_ERROR) << "Unable to write IVF header to file " << file_name;
94 fclose(file);
95 return file_writer;
96 }
97
98 file_writer.reset(new IvfFileWriter(file_name, file));
99 return file_writer;
100 }
101
102 bool IvfFileWriter::WriteFrame(const EncodedImage& encoded_image) {
103 RTC_CHECK(file_ != nullptr);
104
105 if (num_frames_ == 0) {
106 if (!SeekTo(kResolutionOffset))
107 return false;
108 const size_t kResolutionDataSize = 4;
109 uint8_t buffer[kResolutionDataSize];
110 ByteWriter<uint16_t>::WriteLittleEndian(&buffer[0],
111 encoded_image._encodedWidth);
112 ByteWriter<uint16_t>::WriteLittleEndian(&buffer[2],
113 encoded_image._encodedHeight);
114 size_t bytes_written =
115 fwrite(buffer, sizeof(uint8_t), kResolutionDataSize, file_);
116 if (bytes_written != kResolutionDataSize) {
117 LOG(LS_ERROR) << "Unable to write resolution to IVF file " << file_name_;
118 return false;
119 }
120 if (!SeekTo(kIvfHeaderSize))
121 return false;
122 }
123
124 const size_t kFrameHeaderSize = 12;
125 uint8_t frame_header[kFrameHeaderSize] = {};
126 ByteWriter<uint32_t>::WriteLittleEndian(&frame_header[0],
127 encoded_image._length);
128 ByteWriter<uint64_t>::WriteLittleEndian(&frame_header[4],
129 encoded_image.ntp_time_ms_);
130 size_t bytes_written =
131 fwrite(frame_header, sizeof(uint8_t), kFrameHeaderSize, file_);
132 bytes_written += fwrite(encoded_image._buffer, sizeof(uint8_t),
133 encoded_image._length, file_);
134 if (bytes_written != kFrameHeaderSize + encoded_image._length) {
135 LOG(LS_ERROR) << "Unable to write frame to file " << file_name_;
136 return false;
137 }
138
139 ++num_frames_;
140 return true;
141 }
142
143 bool IvfFileWriter::Close() {
144 if (file_ == nullptr)
145 return false;
146
147 if (num_frames_ == 0) {
148 // No frame written to file, remove it entirely.
149 fclose(file_);
150 remove(file_name_.c_str());
151 return true;
152 }
153
154 if (!SeekTo(kFrameCountOffset))
155 return false;
156 const size_t kFrameCountLength = 4;
157 uint8_t size_data[kFrameCountLength];
158 ByteWriter<uint32_t>::WriteLittleEndian(size_data, num_frames_);
159 size_t bytes_written =
160 fwrite(size_data, sizeof(uint8_t), kFrameCountLength, file_);
161 RTC_DCHECK_EQ(kFrameCountLength, bytes_written);
162
163 fflush(file_);
164 fclose(file_);
165 file_ = nullptr;
166
167 return true;
168 }
169
170 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698