Commit | Line | Data |
---|---|---|
72b9787e JB |
1 | /***************************************************************************** |
2 | * Copyright (C) 2013 x265 project | |
3 | * | |
4 | * Authors: Steve Borho <steve@borho.org> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. | |
19 | * | |
20 | * This program is also available under a commercial proprietary license. | |
21 | * For more information, contact us at license @ x265.com. | |
22 | *****************************************************************************/ | |
23 | ||
24 | #include "yuv.h" | |
25 | #include "common.h" | |
26 | ||
27 | #include <iostream> | |
28 | ||
29 | #define ENABLE_THREADING 1 | |
30 | ||
31 | #if _WIN32 | |
32 | #include <io.h> | |
33 | #include <fcntl.h> | |
34 | #if defined(_MSC_VER) | |
35 | #pragma warning(disable: 4996) // POSIX setmode and fileno deprecated | |
36 | #endif | |
37 | #endif | |
38 | ||
39 | using namespace x265; | |
40 | using namespace std; | |
41 | ||
42 | YUVInput::YUVInput(InputFileInfo& info) | |
43 | { | |
44 | for (int i = 0; i < QUEUE_SIZE; i++) | |
45 | buf[i] = NULL; | |
46 | ||
47 | readCount.set(0); | |
48 | writeCount.set(0); | |
49 | depth = info.depth; | |
50 | width = info.width; | |
51 | height = info.height; | |
52 | colorSpace = info.csp; | |
53 | threadActive = false; | |
54 | ifs = NULL; | |
55 | ||
56 | uint32_t pixelbytes = depth > 8 ? 2 : 1; | |
57 | framesize = 0; | |
58 | for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) | |
59 | { | |
60 | uint32_t w = width >> x265_cli_csps[colorSpace].width[i]; | |
61 | uint32_t h = height >> x265_cli_csps[colorSpace].height[i]; | |
62 | framesize += w * h * pixelbytes; | |
63 | } | |
64 | ||
65 | if (width == 0 || height == 0 || info.fpsNum == 0 || info.fpsDenom == 0) | |
66 | { | |
67 | x265_log(NULL, X265_LOG_ERROR, "yuv: width, height, and FPS must be specified\n"); | |
68 | return; | |
69 | } | |
70 | ||
71 | if (!strcmp(info.filename, "-")) | |
72 | { | |
73 | ifs = &cin; | |
74 | #if _WIN32 | |
75 | setmode(fileno(stdin), O_BINARY); | |
76 | #endif | |
77 | } | |
78 | else | |
79 | ifs = new ifstream(info.filename, ios::binary | ios::in); | |
80 | ||
81 | if (ifs && ifs->good()) | |
82 | threadActive = true; | |
83 | else | |
84 | { | |
85 | if (ifs && ifs != &cin) | |
86 | delete ifs; | |
87 | ifs = NULL; | |
88 | return; | |
89 | } | |
90 | ||
91 | for (uint32_t i = 0; i < QUEUE_SIZE; i++) | |
92 | { | |
93 | buf[i] = X265_MALLOC(char, framesize); | |
94 | if (buf[i] == NULL) | |
95 | { | |
96 | x265_log(NULL, X265_LOG_ERROR, "yuv: buffer allocation failure, aborting\n"); | |
97 | threadActive = false; | |
98 | return; | |
99 | } | |
100 | } | |
101 | ||
102 | info.frameCount = -1; | |
103 | ||
104 | /* try to estimate frame count, if this is not stdin */ | |
105 | if (ifs != &cin) | |
106 | { | |
107 | istream::pos_type cur = ifs->tellg(); | |
108 | ||
109 | #if defined(_MSC_VER) && _MSC_VER < 1700 | |
110 | /* Older MSVC versions cannot handle 64bit file sizes properly, so go native */ | |
111 | HANDLE hFile = CreateFileA(info.filename, GENERIC_READ, | |
112 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, | |
113 | FILE_ATTRIBUTE_NORMAL, NULL); | |
114 | if (hFile != INVALID_HANDLE_VALUE) | |
115 | { | |
116 | LARGE_INTEGER size; | |
117 | if (GetFileSizeEx(hFile, &size)) | |
118 | info.frameCount = (int)((size.QuadPart - (int64_t)cur) / framesize); | |
119 | CloseHandle(hFile); | |
120 | } | |
121 | #else // if defined(_MSC_VER) && _MSC_VER < 1700 | |
122 | if (cur >= 0) | |
123 | { | |
124 | ifs->seekg(0, ios::end); | |
125 | istream::pos_type size = ifs->tellg(); | |
126 | ifs->seekg(cur, ios::beg); | |
127 | if (size > 0) | |
128 | info.frameCount = (int)((size - cur) / framesize); | |
129 | } | |
130 | #endif // if defined(_MSC_VER) && _MSC_VER < 1700 | |
131 | } | |
132 | ||
133 | if (info.skipFrames) | |
134 | { | |
135 | #if X86_64 | |
136 | ifs->seekg((uint64_t)framesize * info.skipFrames, ios::cur); | |
137 | #else | |
138 | for (int i = 0; i < info.skipFrames; i++) | |
139 | ifs->ignore(framesize); | |
140 | #endif | |
141 | } | |
142 | } | |
143 | ||
144 | YUVInput::~YUVInput() | |
145 | { | |
146 | if (ifs && ifs != &cin) | |
147 | delete ifs; | |
148 | for (int i = 0; i < QUEUE_SIZE; i++) | |
149 | X265_FREE(buf[i]); | |
150 | } | |
151 | ||
152 | void YUVInput::release() | |
153 | { | |
154 | threadActive = false; | |
155 | readCount.set(readCount.get()); // unblock read thread | |
156 | stop(); | |
157 | delete this; | |
158 | } | |
159 | ||
160 | void YUVInput::startReader() | |
161 | { | |
162 | #if ENABLE_THREADING | |
163 | if (threadActive) | |
164 | start(); | |
165 | #endif | |
166 | } | |
167 | ||
168 | void YUVInput::threadMain() | |
169 | { | |
170 | while (threadActive) | |
171 | { | |
172 | if (!populateFrameQueue()) | |
173 | break; | |
174 | } | |
175 | ||
176 | threadActive = false; | |
177 | writeCount.set(writeCount.get()); // unblock readPicture | |
178 | } | |
179 | ||
180 | bool YUVInput::populateFrameQueue() | |
181 | { | |
182 | if (!ifs || ifs->fail()) | |
183 | return false; | |
184 | ||
185 | /* wait for room in the ring buffer */ | |
186 | int written = writeCount.get(); | |
187 | int read = readCount.get(); | |
188 | while (written - read > QUEUE_SIZE - 2) | |
189 | { | |
190 | read = readCount.waitForChange(read); | |
191 | if (!threadActive) | |
192 | // release() has been called | |
193 | return false; | |
194 | } | |
195 | ||
196 | ifs->read(buf[written % QUEUE_SIZE], framesize); | |
197 | if (ifs->good()) | |
198 | { | |
199 | writeCount.incr(); | |
200 | return true; | |
201 | } | |
202 | else | |
203 | return false; | |
204 | } | |
205 | ||
206 | bool YUVInput::readPicture(x265_picture& pic) | |
207 | { | |
208 | int read = readCount.get(); | |
209 | int written = writeCount.get(); | |
210 | ||
211 | #if ENABLE_THREADING | |
212 | ||
213 | /* only wait if the read thread is still active */ | |
214 | while (threadActive && read == written) | |
215 | written = writeCount.waitForChange(written); | |
216 | ||
217 | #else | |
218 | ||
219 | populateFrameQueue(); | |
220 | ||
221 | #endif // if ENABLE_THREADING | |
222 | ||
223 | if (read < written) | |
224 | { | |
225 | uint32_t pixelbytes = depth > 8 ? 2 : 1; | |
226 | pic.colorSpace = colorSpace; | |
227 | pic.bitDepth = depth; | |
228 | pic.stride[0] = width * pixelbytes; | |
229 | pic.stride[1] = pic.stride[0] >> x265_cli_csps[colorSpace].width[1]; | |
230 | pic.stride[2] = pic.stride[0] >> x265_cli_csps[colorSpace].width[2]; | |
231 | pic.planes[0] = buf[read % QUEUE_SIZE]; | |
232 | pic.planes[1] = (char*)pic.planes[0] + pic.stride[0] * height; | |
233 | pic.planes[2] = (char*)pic.planes[1] + pic.stride[1] * (height >> x265_cli_csps[colorSpace].height[1]); | |
234 | readCount.incr(); | |
235 | return true; | |
236 | } | |
237 | else | |
238 | return false; | |
239 | } |