1 /*****************************************************************************
2 * Copyright (C) 2013 x265 project
4 * Authors: Steve Borho <steve@borho.org>
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.
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.
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.
20 * This program is also available under a commercial proprietary license.
21 * For more information, contact us at license @ x265.com.
22 *****************************************************************************/
29 #define ENABLE_THREADING 1
35 #pragma warning(disable: 4996) // POSIX setmode and fileno deprecated
42 static const char header
[] = "FRAME";
44 Y4MInput::Y4MInput(InputFileInfo
& info
)
46 for (int i
= 0; i
< QUEUE_SIZE
; i
++)
53 colorSpace
= info
.csp
;
54 sarWidth
= info
.sarWidth
;
55 sarHeight
= info
.sarHeight
;
58 rateNum
= info
.fpsNum
;
59 rateDenom
= info
.fpsDenom
;
64 if (!strcmp(info
.filename
, "-"))
68 setmode(fileno(stdin
), O_BINARY
);
72 ifs
= new ifstream(info
.filename
, ios::binary
| ios::in
);
74 if (ifs
&& ifs
->good() && parseHeader())
76 int pixelbytes
= depth
> 8 ? 2 : 1;
77 for (int i
= 0; i
< x265_cli_csps
[colorSpace
].planes
; i
++)
79 int stride
= (width
>> x265_cli_csps
[colorSpace
].width
[i
]) * pixelbytes
;
80 framesize
+= (stride
* (height
>> x265_cli_csps
[colorSpace
].height
[i
]));
84 for (int q
= 0; q
< QUEUE_SIZE
; q
++)
86 buf
[q
] = X265_MALLOC(char, framesize
);
89 x265_log(NULL
, X265_LOG_ERROR
, "y4m: buffer allocation failure, aborting");
97 if (ifs
&& ifs
!= &cin
)
104 info
.height
= height
;
105 info
.sarHeight
= sarHeight
;
106 info
.sarWidth
= sarWidth
;
107 info
.fpsNum
= rateNum
;
108 info
.fpsDenom
= rateDenom
;
109 info
.csp
= colorSpace
;
111 info
.frameCount
= -1;
113 size_t estFrameSize
= framesize
+ strlen(header
) + 1; /* assume basic FRAME\n headers */
115 /* try to estimate frame count, if this is not stdin */
118 istream::pos_type cur
= ifs
->tellg();
120 #if defined(_MSC_VER) && _MSC_VER < 1700
121 /* Older MSVC versions cannot handle 64bit file sizes properly, so go native */
122 HANDLE hFile
= CreateFileA(info
.filename
, GENERIC_READ
,
123 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
124 FILE_ATTRIBUTE_NORMAL
, NULL
);
125 if (hFile
!= INVALID_HANDLE_VALUE
)
128 if (GetFileSizeEx(hFile
, &size
))
129 info
.frameCount
= (int)((size
.QuadPart
- (int64_t)cur
) / estFrameSize
);
132 #else // if defined(_MSC_VER) && _MSC_VER < 1700
135 ifs
->seekg(0, ios::end
);
136 istream::pos_type size
= ifs
->tellg();
137 ifs
->seekg(cur
, ios::beg
);
139 info
.frameCount
= (int)((size
- cur
) / estFrameSize
);
141 #endif // if defined(_MSC_VER) && _MSC_VER < 1700
147 ifs
->seekg((uint64_t)estFrameSize
* info
.skipFrames
, ios::cur
);
149 for (int i
= 0; i
< info
.skipFrames
; i
++)
150 ifs
->ignore(estFrameSize
);
155 Y4MInput::~Y4MInput()
157 if (ifs
&& ifs
!= &cin
)
160 for (int i
= 0; i
< QUEUE_SIZE
; i
++)
164 void Y4MInput::release()
166 threadActive
= false;
167 readCount
.set(readCount
.get()); // unblock file reader
172 bool Y4MInput::parseHeader()
182 // Skip Y4MPEG string
184 while (!ifs
->eof() && (c
!= ' ') && (c
!= '\n'))
189 while (c
== ' ' && !ifs
->eof())
191 // read parameter identifier
200 if (c
== ' ' || c
== '\n')
206 width
= width
* 10 + (c
- '0');
217 if (c
== ' ' || c
== '\n')
223 height
= height
* 10 + (c
- '0');
241 if (c
== ' ' || c
== '\n')
247 rateNum
= rateNum
* 10 + (c
- '0');
248 rateDenom
= rateDenom
* 10;
259 if (c
== ' ' || c
== '\n')
264 rateDenom
= rateDenom
* 10 + (c
- '0');
271 rateNum
= rateNum
* 10 + (c
- '0');
288 if (c
== ' ' || c
== '\n')
293 sarHeight
= sarHeight
* 10 + (c
- '0');
300 sarWidth
= sarWidth
* 10 + (c
- '0');
313 if (c
<= '9' && c
>= '0')
315 csp
= csp
* 10 + (c
- '0');
324 if (c
<= '9' && c
>= '0')
325 d
= d
* 10 + (c
- '0');
335 if (d
>= 8 && d
<= 16)
337 colorSpace
= (csp
== 444) ? X265_CSP_I444
: (csp
== 422) ? X265_CSP_I422
: X265_CSP_I420
;
343 // consume this unsupported configuration word
345 if (c
== ' ' || c
== '\n')
359 if (width
< MIN_FRAME_WIDTH
|| width
> MAX_FRAME_WIDTH
||
360 height
< MIN_FRAME_HEIGHT
|| height
> MAX_FRAME_HEIGHT
||
361 (rateNum
/ rateDenom
) < 1 || (rateNum
/ rateDenom
) > MAX_FRAME_RATE
||
362 colorSpace
<= X265_CSP_I400
|| colorSpace
>= X265_CSP_COUNT
)
368 void Y4MInput::startReader()
376 void Y4MInput::threadMain()
380 if (!populateFrameQueue())
383 while (threadActive
);
385 threadActive
= false;
386 writeCount
.set(writeCount
.get()); // unblock readPicture
389 bool Y4MInput::populateFrameQueue()
391 if (!ifs
|| ifs
->fail())
394 /* strip off the FRAME header */
395 char hbuf
[sizeof(header
)];
397 ifs
->read(hbuf
, strlen(header
));
401 if (!ifs
->good() || memcmp(hbuf
, header
, strlen(header
)))
403 x265_log(NULL
, X265_LOG_ERROR
, "y4m: frame header missing\n");
407 /* consume bytes up to line feed */
409 while (c
!= '\n' && ifs
->good())
412 /* wait for room in the ring buffer */
413 int written
= writeCount
.get();
414 int read
= readCount
.get();
415 while (written
- read
> QUEUE_SIZE
- 2)
417 read
= readCount
.waitForChange(read
);
422 ifs
->read(buf
[written
% QUEUE_SIZE
], framesize
);
432 bool Y4MInput::readPicture(x265_picture
& pic
)
434 int read
= readCount
.get();
435 int written
= writeCount
.get();
439 /* only wait if the read thread is still active */
440 while (threadActive
&& read
== written
)
441 written
= writeCount
.waitForChange(written
);
445 populateFrameQueue();
447 #endif // if ENABLE_THREADING
451 int pixelbytes
= depth
> 8 ? 2 : 1;
452 pic
.bitDepth
= depth
;
453 pic
.colorSpace
= colorSpace
;
454 pic
.stride
[0] = width
* pixelbytes
;
455 pic
.stride
[1] = pic
.stride
[0] >> x265_cli_csps
[colorSpace
].width
[1];
456 pic
.stride
[2] = pic
.stride
[0] >> x265_cli_csps
[colorSpace
].width
[2];
457 pic
.planes
[0] = buf
[read
% QUEUE_SIZE
];
458 pic
.planes
[1] = (char*)pic
.planes
[0] + pic
.stride
[0] * height
;
459 pic
.planes
[2] = (char*)pic
.planes
[1] + pic
.stride
[1] * (height
>> x265_cli_csps
[colorSpace
].height
[1]);