Imported Upstream version 1.4
[deb_x265.git] / source / input / yuv.cpp
CommitLineData
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
39using namespace x265;
40using namespace std;
41
42YUVInput::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
144YUVInput::~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
152void YUVInput::release()
153{
154 threadActive = false;
155 readCount.set(readCount.get()); // unblock read thread
156 stop();
157 delete this;
158}
159
160void YUVInput::startReader()
161{
162#if ENABLE_THREADING
163 if (threadActive)
164 start();
165#endif
166}
167
168void 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
180bool 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
206bool 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}