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