svvitch
digital signage player
D:/vs_workspace/switch_sf/src/svvitch/FFVideoDecoder.cpp
Go to the documentation of this file.
00001 #ifdef USE_FFMPEG
00002 
00003 #include "FFVideoDecoder.h"
00004 #include "PerformanceTimer.h"
00005 
00006 #include <Poco/format.h>
00007 #include <Poco/UnicodeConverter.h>
00008 
00009 
00010 FFVideoDecoder::FFVideoDecoder(Renderer& renderer, AVFormatContext* ic, const int streamNo): FFBaseDecoder(renderer, ic, streamNo),
00011     _outFrame(NULL), _buffer(NULL), _diFrame(NULL), _diBuffer(NULL), _fx(NULL), _worker(NULL), _swsCtx(NULL)
00012 {
00013 }
00014 
00015 FFVideoDecoder::‾FFVideoDecoder() {
00016     Poco::ScopedLock<Poco::FastMutex> lock(_startLock);
00017     _worker = NULL;
00018     _thread.join();
00019 
00020     clearAllFrames();
00021     if (_fx) {
00022         //_log.information("release effect");
00023         SAFE_RELEASE(_fx);
00024     }
00025 }
00026 
00027 bool FFVideoDecoder::isReady() {
00028     return _worker != NULL;
00029 }
00030 
00034 void FFVideoDecoder::clearAllFrames() {
00035     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00036     int count = 0;
00037     while (!_usedFrames.empty()) {
00038         SAFE_DELETE(_usedFrames.front());
00039         _usedFrames.pop();
00040         count++;
00041     }
00042     while (!_frames.empty()) {
00043         SAFE_DELETE(_frames.front());
00044         _frames.pop();
00045         count++;
00046     }
00047     //_log.information(Poco::format("release video frames: %d", count));
00048 }
00049 
00050 void FFVideoDecoder::start() {
00051     Poco::ScopedLock<Poco::FastMutex> lock(_startLock);
00052     AVCodecContext* avctx = _ic->streams[_streamNo]->codec;
00053     // avctx->thread_count = 4;
00054     // int res = avcodec_thread_init(avctx, 4);
00055     // _log.information(Poco::format("thread: %d", res));
00056     int w = avctx->width;
00057     int h = avctx->height;
00058     int flags = SWS_FAST_BILINEAR;
00059     string type;
00060     bool changeFormat = false;
00061     switch (avctx->pix_fmt) {
00062         case PIX_FMT_NONE:
00063             _log.warning("failed pix format NONE");
00064             type = "NONE";
00065             break;
00066         case PIX_FMT_YUV420P:
00067             type = "YUV420P";
00068             _fx = _renderer.createEffect("fx/conversion_yuv2rgb.fx");
00069             if (_fx) {
00070                 changeFormat = false;
00071             } else {
00072                 // エフェクトが生成できない場合
00073                 changeFormat = true;
00074                 flags = SWS_FAST_BILINEAR;
00075             }
00076             break;
00077         case PIX_FMT_YUYV422:
00078             type = "YUYV422";
00079             changeFormat = true;
00080             flags = SWS_FAST_BILINEAR;
00081             break;
00082         case PIX_FMT_RGB24:
00083             type = "RGB24";
00084             changeFormat = true;
00085             break;
00086         case PIX_FMT_BGR24:
00087             type = "BGR24";
00088             changeFormat = true;
00089             break;
00090         case PIX_FMT_ARGB:
00091             type = "RGB32";
00092             changeFormat = true;
00093             break;
00094         case PIX_FMT_YUVJ420P:
00095             type = "YUVJ420P";
00096             _fx = _renderer.createEffect("fx/conversion_yuv2rgb.fx");
00097             if (_fx) {
00098                 changeFormat = false;
00099             } else {
00100                 // エフェクトが生成できない場合
00101                 changeFormat = true;
00102                 flags = SWS_FAST_BILINEAR;
00103             }
00104             break;
00105         case PIX_FMT_YUVJ422P:
00106             type = "YUVJ422P";
00107             // changeFormat = true;
00108             // flags = SWS_FAST_BILINEAR;
00109             _fx = _renderer.createEffect("fx/conversion_yuv2rgb.fx");
00110             if (_fx) {
00111                 changeFormat = false;
00112             } else {
00113                 // エフェクトが生成できない場合
00114                 changeFormat = true;
00115                 flags = SWS_FAST_BILINEAR;
00116             }
00117             break;
00118         case PIX_FMT_YUVJ444P:
00119             type = "YUVJ444P";
00120             changeFormat = true;
00121             break;
00122         default:
00123             type = Poco::format("unknown format(%d)", (int)avctx->pix_fmt);
00124     }
00125 
00126     string size;
00127     if (avctx->sample_aspect_ratio.num) {
00128         _dw = w * avctx->sample_aspect_ratio.num;
00129         _dh = h * avctx->sample_aspect_ratio.den;
00130         size = Poco::format("size(%dx%d DAR %d:%d)", w, h, _dw, _dh);
00131     } else {
00132         _dw = w;
00133         _dh = h;
00134         size = Poco::format("size(%dx%d)", w, h);
00135     }
00136     _log.information(Poco::format("video stream: %s format(%s) %d %s", size, type, avctx->ticks_per_frame, string(avctx->hwaccel?"H/W Acceleted":"")));
00137 
00138     if (changeFormat) {
00139         _outFrame = avcodec_alloc_frame();
00140         if (_outFrame) {
00141             int bytes  = avpicture_get_size(PIX_FMT_BGRA, w, h);
00142             _buffer = (uint8_t*)av_malloc(bytes * sizeof(uint8_t));
00143             if (_buffer) {
00144                 avpicture_fill((AVPicture*)_outFrame, _buffer, PIX_FMT_BGRA, w, h);
00145                 _swsCtx = sws_getContext(w, h, avctx->pix_fmt, w, h, PIX_FMT_BGRA, flags, NULL, NULL, NULL);
00146                 if (_swsCtx) {
00147                     _log.information(Poco::format("change format by sws: %s -> RGB32", type));
00148                 } else {
00149                     _log.warning(Poco::format("failed not create sws context: %s -> RGB32", type));
00150                     av_free(_outFrame);
00151                     av_free(_buffer);
00152                 }
00153             } else {
00154                 _log.warning("failed not allocate buffer");
00155                 av_free(_outFrame);
00156             }
00157         } else {
00158             _log.warning("failed not allocate out frame");
00159         }
00160     } else {
00161         _swsCtx = NULL;
00162     }
00163 
00164     if ((!changeFormat && avctx->pix_fmt != PIX_FMT_NONE) || (changeFormat && _swsCtx)) {
00165         _worker = this;
00166         _thread.start(*_worker);
00167     }
00168 }
00169 
00170 const float FFVideoDecoder::getDisplayAspectRatio() const {
00171     return F(_dw) / _dh;
00172 }
00173 
00174 const UINT FFVideoDecoder::bufferedFrames() {
00175     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00176     //return _frames.size() + bufferedPackets();
00177     return _frames.size();
00178 }
00179 
00180 void FFVideoDecoder::run() {
00181     _log.information("video decoder thread start");
00182     PerformanceTimer timer;
00183 
00184     AVFrame* frame = avcodec_alloc_frame();
00185     int gotPicture = 0;
00186     _readCount = 0;
00187     _avgTime = 0;
00188 
00189     AVPacketList* packetList = NULL;
00190     while (_worker) {
00191         Poco::Thread::sleep(0);
00192         packetList = popPacket();
00193         if (!packetList) {
00194             //Poco::Thread::sleep(10);
00195             continue;
00196         }
00197         timer.start();
00198         AVCodecContext* avctx = _ic->streams[packetList->pkt.stream_index]->codec;
00199         int bytes = avcodec_decode_video2(avctx, frame, &gotPicture, &packetList->pkt);
00200         if (gotPicture) {
00201             const uint8_t* src[4] = {frame->data[0], frame->data[1], frame->data[2], frame->data[3]};
00202             int pos = avctx->frame_number;
00203             int w = avctx->width;
00204             int h = avctx->height;
00205             bool interlaced = frame->interlaced_frame != 0;
00206             PixelFormat format = avctx->pix_fmt;
00207             VideoFrame* vf = popUsedFrame();
00208             if (PIX_FMT_BGRA == format) {
00209                 if (_swsCtx) {
00210                     if (sws_scale(_swsCtx, src, frame->linesize, 0, h, _outFrame->data, _outFrame->linesize) >= 0) {
00211                         if (!vf || !vf->equals(w, h, D3DFMT_A8R8G8B8)) {
00212                             SAFE_DELETE(vf);
00213                             vf = new VideoFrame(_renderer, w, h, _outFrame->linesize, D3DFMT_A8R8G8B8);
00214                         }
00215                         vf->write(_outFrame);
00216                     } else {
00217                         _log.warning("failed sws_scale");
00218                         SAFE_DELETE(vf);
00219                     }
00220 
00221                 } else {
00222                     if (!vf || !vf->equals(w, h, D3DFMT_A8R8G8B8)) {
00223                         SAFE_DELETE(vf);
00224                         vf = new VideoFrame(_renderer, w, h, frame->linesize, D3DFMT_A8R8G8B8);
00225                     }
00226                     vf->write(frame);
00227                 }
00228             } else {
00229                 if (_swsCtx) {
00230                     if (sws_scale(_swsCtx, src, frame->linesize, 0, h, _outFrame->data, _outFrame->linesize) >= 0) {
00231                         if (!vf || !vf->equals(w, h, D3DFMT_X8R8G8B8)) {
00232                             SAFE_DELETE(vf);
00233                             vf = new VideoFrame(_renderer, w, h, _outFrame->linesize, D3DFMT_X8R8G8B8);
00234                         }
00235                         vf->write(_outFrame);
00236                     } else {
00237                         _log.warning("failed sws_scale");
00238                         SAFE_DELETE(vf);
00239                     }
00240 
00241                 } else {
00242                     if (interlaced) {
00243                         // deinterlace
00244                         if (!_diFrame) {
00245                             // deinterlace用のバッファ
00246                             int size = avpicture_get_size(avctx->pix_fmt, frame->linesize[0], h);
00247                             _diBuffer = (uint8_t*)av_malloc(size * sizeof(uint8_t));
00248                             if (_diBuffer) {
00249                                 ZeroMemory(_diBuffer, size);
00250                                 _diFrame = avcodec_alloc_frame();
00251                                 if (_diFrame) {
00252                                     avpicture_fill((AVPicture*)_diFrame, _diBuffer, avctx->pix_fmt, frame->linesize[0], h);
00253                                     _log.information(Poco::format("created deinterlace buffer: %dx%d %d", frame->linesize[0], h, frame->interlaced_frame));
00254                                 } else {
00255                                     av_free(_diBuffer);
00256                                     _diBuffer = NULL;
00257                                 }
00258                             }
00259                         }
00260                         if (_diFrame && avpicture_deinterlace((AVPicture*)_diFrame, (AVPicture*)frame, format, w, h) < 0) {
00261                             _log.warning("failed deinterlace");
00262                             // movのMJPEGがinterlacedではないのにも関わらず、ここに来てしまう。
00263                             if (!vf || !vf->equals(w, h, D3DFMT_L8)) {
00264                                 SAFE_DELETE(vf);
00265                                 switch (format) {
00266                                 case PIX_FMT_YUV420P:
00267                                     vf = new VideoFrame(_renderer, w, h, frame->linesize, h / 2, D3DFMT_L8, _fx);
00268                                     break;
00269                                 case PIX_FMT_YUVJ422P:
00270                                     vf = new VideoFrame(_renderer, w, h, frame->linesize, h, D3DFMT_L8, _fx);
00271                                     break;
00272                                 }
00273                             }
00274                             vf->write(frame);
00275                         } else {
00276                             //インタレ解除できた
00277                             if (!vf || !vf->equals(w, h, D3DFMT_L8)) {
00278                                 SAFE_DELETE(vf);
00279                                 switch (format) {
00280                                 case PIX_FMT_YUV420P:
00281                                     vf = new VideoFrame(_renderer, w, h, frame->linesize, h / 2, D3DFMT_L8, _fx);
00282                                     break;
00283                                 case PIX_FMT_YUVJ422P:
00284                                     vf = new VideoFrame(_renderer, w, h, frame->linesize, h, D3DFMT_L8, _fx);
00285                                     break;
00286                                 }
00287                             }
00288                             vf->write(_diFrame);
00289                         }
00290                     } else {
00291                         if (!vf || !vf->equals(w, h, D3DFMT_L8)) {
00292                             SAFE_DELETE(vf);
00293                             switch (format) {
00294                             case PIX_FMT_YUV420P:
00295                                 vf = new VideoFrame(_renderer, w, h, frame->linesize, h / 2, D3DFMT_L8, _fx);
00296                                 break;
00297                             case PIX_FMT_YUVJ422P:
00298                                 vf = new VideoFrame(_renderer, w, h, frame->linesize, h, D3DFMT_L8, _fx);
00299                                 break;
00300                             }
00301                         }
00302                         vf->write(frame);
00303                     }
00304                 }
00305             }
00306             _readTime = timer.getTime();
00307             _readCount++;
00308             if (_readCount > 0) _avgTime = F(_avgTime * (_readCount - 1) + _readTime) / _readCount;
00309 
00310             if (vf) {
00311                 //UINT textureMen = _renderer.getTextureMem() * 10 / 100;
00312                 //UINT availableTextureMem = _renderer.getAvailableTextureMem();
00313                 while (_worker != NULL && _frames.size() >= 50) {
00314                 //while (_worker != NULL && availableTextureMem < textureMen) {
00315                     // キュー空き待ち
00316                     Poco::Thread::sleep(10);
00317                     //availableTextureMem = _renderer.getAvailableTextureMem();
00318                 }
00319                 {
00320                     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00321                     _frames.push(vf);
00322                     // std::wstring wfile;
00323                     // string file = Poco::format("image%04?i.png", packet.dts);
00324                     // Poco::UnicodeConverter::toUTF16(file, wfile);
00325                     // D3DXSaveTextureToFile(wfile.c_str(), D3DXIFF_PNG, vf->texture[0], NULL);
00326                     // _log.information("queue frame");
00327                 }
00328             } else {
00329                 _log.warning("failed not created video frame");
00330             }
00331 
00332         } else {
00333             // _log.information(Poco::format("video decode not finished: %d", bytes));
00334         }
00335 
00336         av_free_packet(&packetList->pkt);
00337         av_freep(&packetList);
00338     }
00339     if (_swsCtx) {
00340         _log.information("release scaler");
00341         av_free(_outFrame);
00342         _outFrame = NULL;
00343         av_free(_buffer);
00344         _buffer = NULL;
00345         sws_freeContext(_swsCtx);
00346         _swsCtx = NULL;
00347     }
00348 
00349     if (_diFrame) {
00350         _log.information("release deinterlace buffer");
00351         av_free(_diFrame);
00352         _diFrame = NULL;
00353         av_free(_diBuffer);
00354         _diBuffer = NULL;
00355     }
00356 
00357     av_free(frame);
00358     _worker = NULL;
00359     _log.information("video decoder thread end");
00360 }
00361 
00362 VideoFrame* FFVideoDecoder::popUsedFrame() {
00363     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00364     if (_usedFrames.size() > 10) {
00365         VideoFrame* vf = _usedFrames.front();
00366         _usedFrames.pop();
00367         return vf;
00368     }
00369     return NULL;
00370 }
00371 
00372 VideoFrame* FFVideoDecoder::popFrame() {
00373     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00374     if (_frames.size() > 0) {
00375         VideoFrame* vf = _frames.front();
00376         _frames.pop();
00377         return vf;
00378     }
00379     return NULL;
00380 }
00381 
00382 void FFVideoDecoder::pushUsedFrame(VideoFrame* vf) {
00383     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00384     _usedFrames.push(vf);
00385 }
00386 
00387 VideoFrame* FFVideoDecoder::frontFrame() {
00388     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00389     if (_frames.size() > 0) {
00390         VideoFrame* vf = _frames.front();
00391         return vf;
00392     }
00393     return NULL;
00394 }
00395 
00396 VideoFrame* FFVideoDecoder::viewFrame() {
00397     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00398     if (_frames.size() > 0) {
00399         VideoFrame* vf = _frames.back();
00400         return vf;
00401     }
00402     return NULL;
00403 }
00404 
00405 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines