1 /*
2 * libde265 example application "sherlock265".
3 * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
4 *
5 * This file is part of sherlock265, an example application using libde265.
6 *
7 * sherlock265 is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * sherlock265 is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with sherlock265. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "VideoDecoder.hh"
22 #ifdef HAVE_VIDEOGFX
23 #include <libvideogfx.hh>
24 #endif
25
26
27 #ifdef HAVE_VIDEOGFX
28 using namespace videogfx;
29 #endif
30
31 //#include "decctx.h"
32 #include "visualize.h"
33
34
VideoDecoder()35 VideoDecoder::VideoDecoder()
36 : mFH(NULL),
37 ctx(NULL),
38 img(NULL),
39 mNextBuffer(0),
40 mFrameCount(0),
41 mPlayingVideo(false),
42 mVideoEnded(false),
43 mSingleStep(false),
44 mShowDecodedImage(true),
45 mShowQuantPY(false),
46 mCBShowPartitioning(false),
47 mTBShowPartitioning(false),
48 mPBShowPartitioning(false),
49 mShowIntraPredMode(false),
50 mShowPBPredMode(false),
51 mShowMotionVec(false),
52 mShowTiles(false),
53 mShowSlices(false)
54 #ifdef HAVE_SWSCALE
55 , sws(NULL)
56 , width(0)
57 , height(0)
58 #endif
59 {
60 }
61
62
~VideoDecoder()63 VideoDecoder::~VideoDecoder()
64 {
65 free_decoder();
66 #ifdef HAVE_SWSCALE
67 if (sws != NULL) {
68 sws_freeContext(sws);
69 }
70 #endif
71 }
72
run()73 void VideoDecoder::run()
74 {
75 decoder_loop();
76 }
77
78
init(const char * filename)79 void VideoDecoder::init(const char* filename)
80 {
81 init_decoder(filename);
82 }
83
84
startDecoder()85 void VideoDecoder::startDecoder()
86 {
87 if (mPlayingVideo || mVideoEnded) { return; }
88
89 mPlayingVideo=true;
90 exit();
91 }
92
stopDecoder()93 void VideoDecoder::stopDecoder()
94 {
95 if (!mPlayingVideo) { return; }
96
97 mPlayingVideo=false;
98 }
99
singleStepDecoder()100 void VideoDecoder::singleStepDecoder()
101 {
102 if (mPlayingVideo || mVideoEnded) { return; }
103
104 mPlayingVideo=true;
105 mSingleStep=true;
106 exit();
107 }
108
decoder_loop()109 void VideoDecoder::decoder_loop()
110 {
111 for (;;)
112 {
113 if (mPlayingVideo) {
114 mutex.lock();
115
116 if (img) {
117 img = NULL;
118 de265_release_next_picture(ctx);
119 }
120
121 img = de265_peek_next_picture(ctx);
122 while (img==NULL)
123 {
124 mutex.unlock();
125 int more=1;
126 de265_error err = de265_decode(ctx, &more);
127 mutex.lock();
128
129 if (more && err == DE265_OK) {
130 // try again to get picture
131
132 img = de265_peek_next_picture(ctx);
133 }
134 else if (more && err == DE265_ERROR_WAITING_FOR_INPUT_DATA) {
135 uint8_t buf[4096];
136 int buf_size = fread(buf,1,sizeof(buf),mFH);
137 int err = de265_push_data(ctx,buf,buf_size ,0,0);
138 }
139 else if (!more)
140 {
141 mVideoEnded=true;
142 mPlayingVideo=false; // TODO: send signal back
143 break;
144 }
145 }
146
147
148 // show one decoded picture
149
150 if (img) {
151 show_frame(img);
152
153 if (mSingleStep) {
154 mSingleStep=false;
155 mPlayingVideo=false;
156 }
157 }
158
159 mutex.unlock();
160
161 // process events
162
163 QCoreApplication::processEvents();
164 }
165 else {
166 exec();
167 }
168 }
169 }
170
171 #ifdef HAVE_VIDEOGFX
convert_frame_libvideogfx(const de265_image * img,QImage & qimg)172 void VideoDecoder::convert_frame_libvideogfx(const de265_image* img, QImage & qimg)
173 {
174 // --- convert to RGB ---
175
176 Image<Pixel> visu;
177 visu.Create(img->get_width(), img->get_height(), Colorspace_YUV, Chroma_420);
178
179 for (int y=0;y<img->get_height(0);y++) {
180 memcpy(visu.AskFrameY()[y], img->get_image_plane_at_pos(0, 0,y), img->get_width(0));
181 }
182
183 for (int y=0;y<img->get_height(1);y++) {
184 memcpy(visu.AskFrameU()[y], img->get_image_plane_at_pos(1, 0,y), img->get_width(1));
185 }
186
187 for (int y=0;y<img->get_height(2);y++) {
188 memcpy(visu.AskFrameV()[y], img->get_image_plane_at_pos(2, 0,y), img->get_width(2));
189 }
190
191 Image<Pixel> debugvisu;
192 ChangeColorspace(debugvisu, visu, Colorspace_RGB);
193
194 // --- convert to QImage ---
195
196 uchar* ptr = qimg.bits();
197 int bpl = qimg.bytesPerLine();
198
199 for (int y=0;y<img->get_height();y++)
200 {
201 for (int x=0;x<img->get_width();x++)
202 {
203 *(uint32_t*)(ptr+x*4) = ((debugvisu.AskFrameR()[y][x] << 16) |
204 (debugvisu.AskFrameG()[y][x] << 8) |
205 (debugvisu.AskFrameB()[y][x] << 0));
206 }
207
208 ptr += bpl;
209 }
210 }
211 #endif
212
213 #ifdef HAVE_SWSCALE
convert_frame_swscale(const de265_image * img,QImage & qimg)214 void VideoDecoder::convert_frame_swscale(const de265_image* img, QImage & qimg)
215 {
216 if (sws == NULL || img->get_width() != width || img->get_height() != height) {
217 if (sws != NULL) {
218 sws_freeContext(sws);
219 }
220 width = img->get_width();
221 height = img->get_height();
222 sws = sws_getContext(width, height, PIX_FMT_YUV420P, width, height, PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL);
223 }
224
225 int stride[3];
226 const uint8_t *data[3];
227 for (int c=0;c<3;c++) {
228 data[c] = img->get_image_plane(c);
229 stride[c] = img->get_image_stride(c);
230 }
231
232 uint8_t *qdata[1] = { (uint8_t *) qimg.bits() };
233 int qstride[1] = { qimg.bytesPerLine() };
234 sws_scale(sws, data, stride, 0, img->get_height(), qdata, qstride);
235 }
236 #endif
237
show_frame(const de265_image * img)238 void VideoDecoder::show_frame(const de265_image* img)
239 {
240 if (mFrameCount==0) {
241 mImgBuffers[0] = QImage(QSize(img->get_width(),img->get_height()), QImage::Format_RGB32);
242 mImgBuffers[1] = QImage(QSize(img->get_width(),img->get_height()), QImage::Format_RGB32);
243 }
244
245 // --- convert to RGB (or generate a black image if video image is disabled) ---
246
247 QImage* qimg = &mImgBuffers[mNextBuffer];
248 uchar* ptr = qimg->bits();
249 int bpl = qimg->bytesPerLine();
250
251 if (mShowDecodedImage) {
252 #ifdef HAVE_VIDEOGFX
253 convert_frame_libvideogfx(img, *qimg);
254 #elif HAVE_SWSCALE
255 convert_frame_swscale(img, *qimg);
256 #else
257 qimg->fill(QColor(0, 0, 0));
258 #endif
259 } else {
260 qimg->fill(QColor(0, 0, 0));
261 }
262
263 // --- overlay coding-mode visualization ---
264
265 if (mShowQuantPY)
266 {
267 draw_QuantPY(img, ptr, bpl, 4);
268 }
269
270 if (mShowPBPredMode)
271 {
272 draw_PB_pred_modes(img, ptr, bpl, 4);
273 }
274
275 if (mShowIntraPredMode)
276 {
277 draw_intra_pred_modes(img, ptr, bpl, 0x009090ff, 4);
278 }
279
280 if (mTBShowPartitioning)
281 {
282 draw_TB_grid(img, ptr, bpl, 0x00ff6000, 4);
283 }
284
285 if (mPBShowPartitioning)
286 {
287 draw_PB_grid(img, ptr, bpl, 0x00e000, 4);
288 }
289
290 if (mCBShowPartitioning)
291 {
292 draw_CB_grid(img, ptr, bpl, 0x00FFFFFF, 4);
293 }
294
295 if (mShowMotionVec)
296 {
297 draw_Motion(img, ptr, bpl, 4);
298 }
299
300 if (mShowSlices)
301 {
302 draw_Slices(img, ptr, bpl, 4);
303 }
304
305 if (mShowTiles)
306 {
307 draw_Tiles(img, ptr, bpl, 4);
308 }
309
310 emit displayImage(qimg);
311 mNextBuffer = 1-mNextBuffer;
312 mFrameCount++;
313 }
314
315
showCBPartitioning(bool flag)316 void VideoDecoder::showCBPartitioning(bool flag)
317 {
318 mCBShowPartitioning=flag;
319
320 mutex.lock();
321 if (img != NULL) { show_frame(img); }
322 mutex.unlock();
323 }
324
325
showTBPartitioning(bool flag)326 void VideoDecoder::showTBPartitioning(bool flag)
327 {
328 mTBShowPartitioning=flag;
329
330 mutex.lock();
331 if (img != NULL) { show_frame(img); }
332 mutex.unlock();
333 }
334
showPBPartitioning(bool flag)335 void VideoDecoder::showPBPartitioning(bool flag)
336 {
337 mPBShowPartitioning=flag;
338
339 mutex.lock();
340 if (img != NULL) { show_frame(img); }
341 mutex.unlock();
342 }
343
showIntraPredMode(bool flag)344 void VideoDecoder::showIntraPredMode(bool flag)
345 {
346 mShowIntraPredMode=flag;
347
348 mutex.lock();
349 if (img != NULL) { show_frame(img); }
350 mutex.unlock();
351 }
352
showPBPredMode(bool flag)353 void VideoDecoder::showPBPredMode(bool flag)
354 {
355 mShowPBPredMode=flag;
356
357 mutex.lock();
358 if (img != NULL) { show_frame(img); }
359 mutex.unlock();
360 }
361
showQuantPY(bool flag)362 void VideoDecoder::showQuantPY(bool flag)
363 {
364 mShowQuantPY=flag;
365
366 mutex.lock();
367 if (img != NULL) { show_frame(img); }
368 mutex.unlock();
369 }
370
showMotionVec(bool flag)371 void VideoDecoder::showMotionVec(bool flag)
372 {
373 mShowMotionVec=flag;
374
375 mutex.lock();
376 if (img != NULL) { show_frame(img); }
377 mutex.unlock();
378 }
379
showDecodedImage(bool flag)380 void VideoDecoder::showDecodedImage(bool flag)
381 {
382 mShowDecodedImage=flag;
383
384 mutex.lock();
385 if (img != NULL) { show_frame(img); }
386 mutex.unlock();
387 }
388
showTiles(bool flag)389 void VideoDecoder::showTiles(bool flag)
390 {
391 mShowTiles=flag;
392
393 mutex.lock();
394 if (img != NULL) { show_frame(img); }
395 mutex.unlock();
396 }
397
showSlices(bool flag)398 void VideoDecoder::showSlices(bool flag)
399 {
400 mShowSlices=flag;
401
402 mutex.lock();
403 if (img != NULL) { show_frame(img); }
404 mutex.unlock();
405 }
406
407
408
409
init_decoder(const char * filename)410 void VideoDecoder::init_decoder(const char* filename)
411 {
412 mFH = fopen(filename,"rb");
413 //init_file_context(&inputctx, filename);
414 //rbsp_buffer_init(&buf);
415
416 ctx = de265_new_decoder();
417 de265_start_worker_threads(ctx, 4); // start 4 background threads
418 }
419
free_decoder()420 void VideoDecoder::free_decoder()
421 {
422 if (mFH) { fclose(mFH); }
423
424 if (ctx) { de265_free_decoder(ctx); }
425 }
426