1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "DVDVideoCodecFFmpeg.h"
10 
11 #include "DVDCodecs/DVDCodecs.h"
12 #include "DVDCodecs/DVDFactoryCodec.h"
13 #include "DVDStreamInfo.h"
14 #include "ServiceBroker.h"
15 #include "cores/VideoPlayer/Interface/TimingConstants.h"
16 #include "cores/VideoPlayer/VideoRenderers/RenderManager.h"
17 #include "cores/VideoSettings.h"
18 #include "settings/AdvancedSettings.h"
19 #include "settings/Settings.h"
20 #include "settings/SettingsComponent.h"
21 #include "utils/CPUInfo.h"
22 #include "utils/StringUtils.h"
23 #include "utils/XTimeUtils.h"
24 #include "utils/log.h"
25 
26 #include <memory>
27 
28 #include "system.h"
29 
30 extern "C" {
31 #include <libavutil/opt.h>
32 #include <libavutil/mastering_display_metadata.h>
33 #include <libavfilter/avfilter.h>
34 #include <libavfilter/buffersink.h>
35 #include <libavfilter/buffersrc.h>
36 #include <libavutil/pixdesc.h>
37 }
38 
39 #ifndef TARGET_POSIX
40 #define RINT(x) ((x) >= 0 ? ((int)((x) + 0.5)) : ((int)((x) - 0.5)))
41 #else
42 #include <math.h>
43 #define RINT lrint
44 #endif
45 
46 enum DecoderState
47 {
48   STATE_NONE,
49   STATE_SW_SINGLE,
50   STATE_HW_SINGLE,
51   STATE_HW_FAILED,
52   STATE_SW_MULTI
53 };
54 
55 enum EFilterFlags {
56   FILTER_NONE                =  0x0,
57   FILTER_DEINTERLACE_YADIF   =  0x1,  //< use first deinterlace mode
58   FILTER_DEINTERLACE_ANY     =  0xf,  //< use any deinterlace mode
59   FILTER_DEINTERLACE_FLAGGED = 0x10,  //< only deinterlace flagged frames
60   FILTER_DEINTERLACE_HALFED  = 0x20,  //< do half rate deinterlacing
61   FILTER_ROTATE              = 0x40,  //< rotate image according to the codec hints
62 };
63 
64 //------------------------------------------------------------------------------
65 // Video Buffers
66 //------------------------------------------------------------------------------
67 
68 class CVideoBufferFFmpeg : public CVideoBuffer
69 {
70 public:
71   CVideoBufferFFmpeg(IVideoBufferPool &pool, int id);
72   ~CVideoBufferFFmpeg() override;
73   void GetPlanes(uint8_t*(&planes)[YuvImage::MAX_PLANES]) override;
74   void GetStrides(int(&strides)[YuvImage::MAX_PLANES]) override;
75 
76   void SetRef(AVFrame *frame);
77   void Unref();
78 
79 protected:
80   AVFrame* m_pFrame;
81 };
82 
CVideoBufferFFmpeg(IVideoBufferPool & pool,int id)83 CVideoBufferFFmpeg::CVideoBufferFFmpeg(IVideoBufferPool &pool, int id)
84 : CVideoBuffer(id)
85 {
86   m_pFrame = av_frame_alloc();
87 }
88 
~CVideoBufferFFmpeg()89 CVideoBufferFFmpeg::~CVideoBufferFFmpeg()
90 {
91   av_frame_free(&m_pFrame);
92 }
93 
GetPlanes(uint8_t * (& planes)[YuvImage::MAX_PLANES])94 void CVideoBufferFFmpeg::GetPlanes(uint8_t*(&planes)[YuvImage::MAX_PLANES])
95 {
96   planes[0] = m_pFrame->data[0];
97   planes[1] = m_pFrame->data[1];
98   planes[2] = m_pFrame->data[2];
99 }
100 
GetStrides(int (& strides)[YuvImage::MAX_PLANES])101 void CVideoBufferFFmpeg::GetStrides(int(&strides)[YuvImage::MAX_PLANES])
102 {
103   strides[0] = m_pFrame->linesize[0];
104   strides[1] = m_pFrame->linesize[1];
105   strides[2] = m_pFrame->linesize[2];
106 }
107 
SetRef(AVFrame * frame)108 void CVideoBufferFFmpeg::SetRef(AVFrame *frame)
109 {
110   av_frame_unref(m_pFrame);
111   av_frame_move_ref(m_pFrame, frame);
112   m_pixFormat = (AVPixelFormat)m_pFrame->format;
113 }
114 
Unref()115 void CVideoBufferFFmpeg::Unref()
116 {
117   av_frame_unref(m_pFrame);
118 }
119 
120 //------------------------------------------------------------------------------
121 
122 class CVideoBufferPoolFFmpeg : public IVideoBufferPool
123 {
124 public:
125   ~CVideoBufferPoolFFmpeg() override;
126   void Return(int id) override;
127   CVideoBuffer* Get() override;
128 
129 protected:
130   CCriticalSection m_critSection;
131   std::vector<CVideoBufferFFmpeg*> m_all;
132   std::deque<int> m_used;
133   std::deque<int> m_free;
134 };
135 
~CVideoBufferPoolFFmpeg()136 CVideoBufferPoolFFmpeg::~CVideoBufferPoolFFmpeg()
137 {
138   for (auto buf : m_all)
139   {
140     delete buf;
141   }
142 }
143 
Get()144 CVideoBuffer* CVideoBufferPoolFFmpeg::Get()
145 {
146   CSingleLock lock(m_critSection);
147 
148   CVideoBufferFFmpeg *buf = nullptr;
149   if (!m_free.empty())
150   {
151     int idx = m_free.front();
152     m_free.pop_front();
153     m_used.push_back(idx);
154     buf = m_all[idx];
155   }
156   else
157   {
158     int id = m_all.size();
159     buf = new CVideoBufferFFmpeg(*this, id);
160     m_all.push_back(buf);
161     m_used.push_back(id);
162   }
163 
164   buf->Acquire(GetPtr());
165   return buf;
166 }
167 
Return(int id)168 void CVideoBufferPoolFFmpeg::Return(int id)
169 {
170   CSingleLock lock(m_critSection);
171 
172   m_all[id]->Unref();
173   auto it = m_used.begin();
174   while (it != m_used.end())
175   {
176     if (*it == id)
177     {
178       m_used.erase(it);
179       break;
180     }
181     else
182       ++it;
183   }
184   m_free.push_back(id);
185 }
186 
187 //------------------------------------------------------------------------------
188 // main class
189 //------------------------------------------------------------------------------
190 
CDropControl()191 CDVDVideoCodecFFmpeg::CDropControl::CDropControl()
192 {
193   Reset(true);
194 }
195 
Reset(bool init)196 void CDVDVideoCodecFFmpeg::CDropControl::Reset(bool init)
197 {
198   m_lastPTS = AV_NOPTS_VALUE;
199 
200   if (init || m_state != VALID)
201   {
202     m_count = 0;
203     m_diffPTS = 0;
204     m_state = INIT;
205   }
206 }
207 
Process(int64_t pts,bool drop)208 void CDVDVideoCodecFFmpeg::CDropControl::Process(int64_t pts, bool drop)
209 {
210   if (m_state == INIT)
211   {
212     if (pts != AV_NOPTS_VALUE && m_lastPTS != AV_NOPTS_VALUE)
213     {
214       m_diffPTS += pts - m_lastPTS;
215       m_count++;
216     }
217     if (m_count > 10)
218     {
219       m_diffPTS = m_diffPTS / m_count;
220       if (m_diffPTS > 0)
221       {
222         CLog::Log(LOGINFO, "CDVDVideoCodecFFmpeg::CDropControl: calculated diff time: %" PRId64,
223                   m_diffPTS);
224         m_state = CDropControl::VALID;
225         m_count = 0;
226       }
227     }
228   }
229   else if (m_state == VALID && !drop)
230   {
231     if (std::abs(pts - m_lastPTS - m_diffPTS) > m_diffPTS * 0.2)
232     {
233       m_count++;
234       if (m_count > 5)
235       {
236         CLog::Log(LOGINFO, "CDVDVideoCodecFFmpeg::CDropControl: lost diff");
237         Reset(true);
238       }
239     }
240     else
241       m_count = 0;
242   }
243   m_lastPTS = pts;
244 }
245 
GetFormat(struct AVCodecContext * avctx,const AVPixelFormat * fmt)246 enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat(struct AVCodecContext * avctx, const AVPixelFormat * fmt)
247 {
248   ICallbackHWAccel *cb = static_cast<ICallbackHWAccel*>(avctx->opaque);
249   CDVDVideoCodecFFmpeg* ctx  = dynamic_cast<CDVDVideoCodecFFmpeg*>(cb);
250 
251   const char* pixFmtName = av_get_pix_fmt_name(*fmt);
252 
253   ctx->m_processInfo.SetVideoDimensions(avctx->coded_width, avctx->coded_height);
254 
255   // if frame threading is enabled hw accel is not allowed
256   // 2nd condition:
257   // fix an ffmpeg issue here, it calls us with an invalid profile
258   // then a 2nd call with a valid one
259   if(ctx->m_decoderState != STATE_HW_SINGLE ||
260      (avctx->codec_id == AV_CODEC_ID_VC1 && avctx->profile == FF_PROFILE_UNKNOWN))
261   {
262     AVPixelFormat defaultFmt = avcodec_default_get_format(avctx, fmt);
263     pixFmtName = av_get_pix_fmt_name(defaultFmt);
264     ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : "");
265     ctx->m_processInfo.SetSwDeinterlacingMethods();
266     return defaultFmt;
267   }
268 
269   // hardware decoder de-selected, restore standard ffmpeg
270   if (ctx->HasHardware())
271   {
272     ctx->SetHardware(nullptr);
273     avctx->get_buffer2 = avcodec_default_get_buffer2;
274     avctx->slice_flags = 0;
275     av_buffer_unref(&avctx->hw_frames_ctx);
276   }
277 
278   const AVPixelFormat * cur = fmt;
279   while (*cur != AV_PIX_FMT_NONE)
280   {
281     pixFmtName = av_get_pix_fmt_name(*cur);
282 
283     auto hwaccels = CDVDFactoryCodec::GetHWAccels();
284     for (auto &hwaccel : hwaccels)
285     {
286       IHardwareDecoder *pDecoder(CDVDFactoryCodec::CreateVideoCodecHWAccel(hwaccel, ctx->m_hints,
287                                                                            ctx->m_processInfo, *cur));
288       if (pDecoder)
289       {
290         if (pDecoder->Open(avctx, ctx->m_pCodecContext, *cur))
291         {
292           ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : "");
293           ctx->SetHardware(pDecoder);
294           return *cur;
295         }
296       }
297       SAFE_RELEASE(pDecoder);
298     }
299     cur++;
300   }
301 
302   ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : "");
303   ctx->m_decoderState = STATE_HW_FAILED;
304   return avcodec_default_get_format(avctx, fmt);
305 }
306 
CDVDVideoCodecFFmpeg(CProcessInfo & processInfo)307 CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg(CProcessInfo &processInfo)
308 : CDVDVideoCodec(processInfo), m_postProc(processInfo)
309 {
310   m_videoBufferPool = std::make_shared<CVideoBufferPoolFFmpeg>();
311 
312   m_decoderState = STATE_NONE;
313 }
314 
~CDVDVideoCodecFFmpeg()315 CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg()
316 {
317   Dispose();
318 }
319 
Open(CDVDStreamInfo & hints,CDVDCodecOptions & options)320 bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
321 {
322   if (hints.cryptoSession)
323   {
324     CLog::Log(LOGERROR,"CDVDVideoCodecFFmpeg::Open() CryptoSessions unsupported!");
325     return false;
326   }
327 
328   m_hints = hints;
329   m_options = options;
330 
331   AVCodec* pCodec;
332 
333   m_iOrientation = hints.orientation;
334 
335   m_formats.clear();
336   m_formats = m_processInfo.GetPixFormats();
337   m_formats.push_back(AV_PIX_FMT_NONE); /* always add none to get a terminated list in ffmpeg world */
338   m_processInfo.SetSwDeinterlacingMethods();
339   m_processInfo.SetVideoInterlaced(false);
340 
341   pCodec = avcodec_find_decoder(hints.codec);
342 
343   if(pCodec == NULL)
344   {
345     CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
346     return false;
347   }
348 
349   CLog::Log(LOGINFO, "CDVDVideoCodecFFmpeg::Open() Using codec: %s",
350             pCodec->long_name ? pCodec->long_name : pCodec->name);
351 
352   m_pCodecContext = avcodec_alloc_context3(pCodec);
353   if (!m_pCodecContext)
354     return false;
355 
356   m_pCodecContext->opaque = static_cast<ICallbackHWAccel*>(this);
357   m_pCodecContext->debug_mv = 0;
358   m_pCodecContext->debug = 0;
359   m_pCodecContext->workaround_bugs = FF_BUG_AUTODETECT;
360   m_pCodecContext->get_format = GetFormat;
361   m_pCodecContext->codec_tag = hints.codec_tag;
362 
363   // setup threading model
364   if (!(hints.codecOptions & CODEC_FORCE_SOFTWARE))
365   {
366     if (m_decoderState == STATE_NONE)
367     {
368       m_decoderState = STATE_HW_SINGLE;
369     }
370     else
371     {
372       int num_threads = CServiceBroker::GetCPUInfo()->GetCPUCount() * 3 / 2;
373       num_threads = std::max(1, std::min(num_threads, 16));
374       m_pCodecContext->thread_count = num_threads;
375       m_pCodecContext->thread_safe_callbacks = 1;
376       m_decoderState = STATE_SW_MULTI;
377       CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg - open frame threaded with %d threads", num_threads);
378     }
379   }
380   else
381     m_decoderState = STATE_SW_SINGLE;
382 
383   // if we don't do this, then some codecs seem to fail.
384   m_pCodecContext->coded_height = hints.height;
385   m_pCodecContext->coded_width = hints.width;
386   m_pCodecContext->bits_per_coded_sample = hints.bitsperpixel;
387 
388   if( hints.extradata && hints.extrasize > 0 )
389   {
390     m_pCodecContext->extradata_size = hints.extrasize;
391     m_pCodecContext->extradata = (uint8_t*)av_mallocz(hints.extrasize + AV_INPUT_BUFFER_PADDING_SIZE);
392     memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
393   }
394 
395   // advanced setting override for skip loop filter (see avcodec.h for valid options)
396   //! @todo allow per video setting?
397   int iSkipLoopFilter = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iSkipLoopFilter;
398   if (iSkipLoopFilter != 0)
399   {
400     m_pCodecContext->skip_loop_filter = static_cast<AVDiscard>(iSkipLoopFilter);
401   }
402 
403   // set any special options
404   for(std::vector<CDVDCodecOption>::iterator it = options.m_keys.begin(); it != options.m_keys.end(); ++it)
405   {
406     av_opt_set(m_pCodecContext, it->m_name.c_str(), it->m_value.c_str(), 0);
407   }
408 
409   if (avcodec_open2(m_pCodecContext, pCodec, nullptr) < 0)
410   {
411     CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to open codec");
412     avcodec_free_context(&m_pCodecContext);
413     return false;
414   }
415 
416   m_pFrame = av_frame_alloc();
417   if (!m_pFrame)
418   {
419     avcodec_free_context(&m_pCodecContext);
420     return false;
421   }
422 
423   m_pDecodedFrame = av_frame_alloc();
424   if (!m_pDecodedFrame)
425   {
426     av_frame_free(&m_pFrame);
427     avcodec_free_context(&m_pCodecContext);
428     return false;
429   }
430 
431   m_pFilterFrame = av_frame_alloc();
432   if (!m_pFilterFrame)
433   {
434     av_frame_free(&m_pFrame);
435     av_frame_free(&m_pDecodedFrame);
436     avcodec_free_context(&m_pCodecContext);
437     return false;
438   }
439 
440   UpdateName();
441   const char* pixFmtName = av_get_pix_fmt_name(m_pCodecContext->pix_fmt);
442   m_processInfo.SetVideoDimensions(m_pCodecContext->coded_width, m_pCodecContext->coded_height);
443   m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : "");
444 
445   m_dropCtrl.Reset(true);
446   m_eof = false;
447   return true;
448 }
449 
Dispose()450 void CDVDVideoCodecFFmpeg::Dispose()
451 {
452   av_frame_free(&m_pFrame);
453   av_frame_free(&m_pDecodedFrame);
454   av_frame_free(&m_pFilterFrame);
455   avcodec_free_context(&m_pCodecContext);
456   SAFE_RELEASE(m_pHardware);
457 
458   FilterClose();
459 }
460 
SetFilters()461 void CDVDVideoCodecFFmpeg::SetFilters()
462 {
463   // ask codec to do deinterlacing if possible
464   EINTERLACEMETHOD mInt = m_processInfo.GetVideoSettings().m_InterlaceMethod;
465 
466   if (!m_processInfo.Supports(mInt))
467     mInt = m_processInfo.GetFallbackDeintMethod();
468 
469   unsigned int filters = 0;
470 
471   if (mInt != VS_INTERLACEMETHOD_NONE && m_interlaced)
472   {
473     if (mInt == VS_INTERLACEMETHOD_DEINTERLACE)
474       filters = FILTER_DEINTERLACE_ANY;
475     else if (mInt == VS_INTERLACEMETHOD_DEINTERLACE_HALF)
476       filters = FILTER_DEINTERLACE_ANY | FILTER_DEINTERLACE_HALFED;
477 
478     if (filters)
479       filters |= FILTER_DEINTERLACE_FLAGGED;
480   }
481 
482   if (m_codecControlFlags & DVD_CODEC_CTRL_ROTATE)
483     filters |= FILTER_ROTATE;
484 
485   m_filters_next.clear();
486 
487   if (filters & FILTER_ROTATE)
488   {
489     switch(m_iOrientation)
490     {
491       case 90:
492         m_filters_next += "transpose=1";
493         break;
494       case 180:
495         m_filters_next += "vflip,hflip";
496         break;
497       case 270:
498         m_filters_next += "transpose=2";
499         break;
500       default:
501         break;
502       }
503   }
504 
505   if (filters & FILTER_DEINTERLACE_YADIF)
506   {
507     if (filters & FILTER_DEINTERLACE_HALFED)
508       m_filters_next = "yadif=0:-1";
509     else
510       m_filters_next = "yadif=1:-1";
511 
512     if (filters & FILTER_DEINTERLACE_FLAGGED)
513       m_filters_next += ":1";
514   }
515 }
516 
UpdateName()517 void CDVDVideoCodecFFmpeg::UpdateName()
518 {
519   if(m_pCodecContext->codec->name)
520     m_name = std::string("ff-") + m_pCodecContext->codec->name;
521   else
522     m_name = "ffmpeg";
523 
524   if(m_pHardware)
525     m_name += "-" + m_pHardware->Name();
526 
527   m_processInfo.SetVideoDecoderName(m_name, m_pHardware ? true : false);
528 
529   CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg - Updated codec: %s", m_name.c_str());
530 }
531 
532 union pts_union
533 {
534   double  pts_d;
535   int64_t pts_i;
536 };
537 
pts_dtoi(double pts)538 static int64_t pts_dtoi(double pts)
539 {
540   pts_union u;
541   u.pts_d = pts;
542   return u.pts_i;
543 }
544 
AddData(const DemuxPacket & packet)545 bool CDVDVideoCodecFFmpeg::AddData(const DemuxPacket &packet)
546 {
547   if (!m_pCodecContext)
548     return true;
549 
550   if (!packet.pData)
551     return true;
552 
553   if (m_eof)
554   {
555     Reset();
556   }
557 
558   if (packet.recoveryPoint)
559     m_started = true;
560 
561   m_dts = packet.dts;
562   m_pCodecContext->reordered_opaque = pts_dtoi(packet.pts);
563 
564   AVPacket avpkt;
565   av_init_packet(&avpkt);
566   avpkt.data = packet.pData;
567   avpkt.size = packet.iSize;
568   avpkt.dts = (packet.dts == DVD_NOPTS_VALUE) ? AV_NOPTS_VALUE : static_cast<int64_t>(packet.dts / DVD_TIME_BASE * AV_TIME_BASE);
569   avpkt.pts = (packet.pts == DVD_NOPTS_VALUE) ? AV_NOPTS_VALUE : static_cast<int64_t>(packet.pts / DVD_TIME_BASE * AV_TIME_BASE);
570   avpkt.side_data = static_cast<AVPacketSideData*>(packet.pSideData);
571   avpkt.side_data_elems = packet.iSideDataElems;
572 
573   int ret = avcodec_send_packet(m_pCodecContext, &avpkt);
574 
575   // try again
576   if (ret == AVERROR(EAGAIN))
577   {
578     return false;
579   }
580   // error
581   else if (ret)
582   {
583     // handle VC_NOBUFFER error for hw accel
584     if (m_pHardware)
585     {
586       int result = m_pHardware->Check(m_pCodecContext);
587       if (result == VC_NOBUFFER)
588       {
589         return false;
590       }
591     }
592   }
593 
594   m_iLastKeyframe++;
595   // put a limit on convergence count to avoid huge mem usage on streams without keyframes
596   if (m_iLastKeyframe > 300)
597     m_iLastKeyframe = 300;
598 
599   m_startedInput = true;
600 
601   return true;
602 }
603 
GetPicture(VideoPicture * pVideoPicture)604 CDVDVideoCodec::VCReturn CDVDVideoCodecFFmpeg::GetPicture(VideoPicture* pVideoPicture)
605 {
606   if (!m_startedInput)
607   {
608     return VC_BUFFER;
609   }
610   else if (m_eof)
611   {
612     return VC_EOF;
613   }
614 
615   // handle hw accelerators first, they may have frames ready
616   if (m_pHardware)
617   {
618     int flags = m_codecControlFlags;
619     flags &= ~DVD_CODEC_CTRL_DRAIN;
620     m_pHardware->SetCodecControl(flags);
621     CDVDVideoCodec::VCReturn ret = m_pHardware->Decode(m_pCodecContext, nullptr);
622     if (ret == VC_PICTURE)
623     {
624       if (m_pHardware->GetPicture(m_pCodecContext, pVideoPicture))
625         return VC_PICTURE;
626       else
627         return VC_ERROR;
628     }
629     else if (ret == VC_BUFFER)
630       ;
631     else
632       return ret;
633   }
634   else if (m_pFilterGraph && !m_filterEof)
635   {
636     CDVDVideoCodec::VCReturn ret = FilterProcess(nullptr);
637     if (ret == VC_PICTURE)
638     {
639       if (!SetPictureParams(pVideoPicture))
640         return VC_ERROR;
641       return VC_PICTURE;
642     }
643     else if (ret == VC_BUFFER)
644       ;
645     else
646       return ret;
647   }
648 
649   // process ffmpeg
650   if (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)
651   {
652     AVPacket avpkt;
653     av_init_packet(&avpkt);
654     avpkt.data = nullptr;
655     avpkt.size = 0;
656     avpkt.dts = AV_NOPTS_VALUE;
657     avpkt.pts = AV_NOPTS_VALUE;
658     avcodec_send_packet(m_pCodecContext, &avpkt);
659   }
660 
661   int ret = avcodec_receive_frame(m_pCodecContext, m_pDecodedFrame);
662 
663   if (m_decoderState == STATE_HW_FAILED && !m_pHardware)
664     return VC_REOPEN;
665 
666   if(m_iLastKeyframe < m_pCodecContext->has_b_frames + 2)
667     m_iLastKeyframe = m_pCodecContext->has_b_frames + 2;
668 
669   if (ret == AVERROR_EOF)
670   {
671     // next drain hw accel or filter
672     if (m_pHardware)
673     {
674       int flags = m_codecControlFlags;
675       flags |= DVD_CODEC_CTRL_DRAIN;
676       m_pHardware->SetCodecControl(flags);
677       int ret = m_pHardware->Decode(m_pCodecContext, nullptr);
678       if (ret == VC_PICTURE)
679       {
680         if (m_pHardware->GetPicture(m_pCodecContext, pVideoPicture))
681           return VC_PICTURE;
682         else
683           return VC_ERROR;
684       }
685       else
686       {
687         m_eof = true;
688         CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg::GetPicture - eof hw accel");
689         return VC_EOF;
690       }
691     }
692     else if (m_pFilterGraph && !m_filterEof)
693     {
694       int ret = FilterProcess(nullptr);
695       if (ret == VC_PICTURE)
696       {
697         if (!SetPictureParams(pVideoPicture))
698           return VC_ERROR;
699         else
700           return VC_PICTURE;
701       }
702       else
703       {
704         m_eof = true;
705         CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg::GetPicture - eof filter");
706         return VC_EOF;
707       }
708     }
709     else
710     {
711       m_eof = true;
712       CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg::GetPicture - eof");
713       return VC_EOF;
714     }
715   }
716   else if (ret == AVERROR(EAGAIN))
717   {
718     return VC_BUFFER;
719   }
720   else if (ret)
721   {
722     CLog::Log(LOGERROR, "%s - avcodec_receive_frame returned failure", __FUNCTION__);
723     return VC_ERROR;
724   }
725 
726   // here we got a frame
727   int64_t framePTS = m_pDecodedFrame->best_effort_timestamp;
728 
729   if (m_pCodecContext->skip_frame > AVDISCARD_DEFAULT)
730   {
731     if (m_dropCtrl.m_state == CDropControl::VALID &&
732         m_dropCtrl.m_lastPTS != AV_NOPTS_VALUE &&
733         framePTS != AV_NOPTS_VALUE &&
734         framePTS > (m_dropCtrl.m_lastPTS + m_dropCtrl.m_diffPTS * 1.5))
735     {
736       m_droppedFrames++;
737       if (m_interlaced)
738         m_droppedFrames++;
739     }
740   }
741   m_dropCtrl.Process(framePTS, m_pCodecContext->skip_frame > AVDISCARD_DEFAULT);
742 
743   if (m_pDecodedFrame->key_frame)
744   {
745     m_started = true;
746     m_iLastKeyframe = m_pCodecContext->has_b_frames + 2;
747   }
748   if (m_pDecodedFrame->interlaced_frame)
749     m_interlaced = true;
750   else
751     m_interlaced = false;
752 
753   if (!m_processInfo.GetVideoInterlaced() && m_interlaced)
754     m_processInfo.SetVideoInterlaced(m_interlaced);
755 
756   if (!m_started)
757   {
758     int frames = 300;
759     if (m_dropCtrl.m_state == CDropControl::VALID)
760       frames = static_cast<int>(6000000 / m_dropCtrl.m_diffPTS);
761     if (m_iLastKeyframe >= frames && m_pDecodedFrame->pict_type == AV_PICTURE_TYPE_I)
762     {
763       m_started = true;
764     }
765     else
766     {
767       av_frame_unref(m_pDecodedFrame);
768       return VC_BUFFER;
769     }
770   }
771 
772   // push the frame to hw decoder for further processing
773   if (m_pHardware)
774   {
775     av_frame_unref(m_pFrame);
776     av_frame_move_ref(m_pFrame, m_pDecodedFrame);
777     CDVDVideoCodec::VCReturn ret = m_pHardware->Decode(m_pCodecContext, m_pFrame);
778     if (ret == VC_FLUSHED)
779     {
780       Reset();
781       return ret;
782     }
783     else if (ret == VC_FATAL)
784     {
785       m_decoderState = STATE_HW_FAILED;
786       return VC_REOPEN;
787     }
788     else if (ret == VC_PICTURE)
789     {
790       if (m_pHardware->GetPicture(m_pCodecContext, pVideoPicture))
791         return VC_PICTURE;
792       else
793         return VC_ERROR;
794     }
795 
796     return ret;
797   }
798   // process filters for sw decoding
799   else
800   {
801     SetFilters();
802 
803     bool need_scale = std::find(m_formats.begin(),
804                                 m_formats.end(),
805                                 m_pCodecContext->pix_fmt) == m_formats.end();
806 
807     bool need_reopen = false;
808     if (m_filters != m_filters_next)
809       need_reopen = true;
810 
811     if (!m_filters_next.empty() && m_filterEof)
812       need_reopen = true;
813 
814     if (m_pFilterIn)
815     {
816       if (m_pFilterIn->outputs[0]->format != m_pCodecContext->pix_fmt ||
817           m_pFilterIn->outputs[0]->w != m_pCodecContext->width ||
818           m_pFilterIn->outputs[0]->h != m_pCodecContext->height)
819         need_reopen = true;
820     }
821 
822     // try to setup new filters
823     if (need_reopen || (need_scale && m_pFilterGraph == nullptr))
824     {
825       m_filters = m_filters_next;
826 
827       if (FilterOpen(m_filters, need_scale) < 0)
828         FilterClose();
829     }
830 
831     if (m_pFilterGraph && !m_filterEof)
832     {
833       CDVDVideoCodec::VCReturn ret = FilterProcess(m_pDecodedFrame);
834       if (ret != VC_PICTURE)
835         return VC_NONE;
836     }
837     else
838     {
839       av_frame_unref(m_pFrame);
840       av_frame_move_ref(m_pFrame, m_pDecodedFrame);
841     }
842 
843     if (!SetPictureParams(pVideoPicture))
844       return VC_ERROR;
845     else
846       return VC_PICTURE;
847   }
848 
849   return VC_NONE;
850 }
851 
SetPictureParams(VideoPicture * pVideoPicture)852 bool CDVDVideoCodecFFmpeg::SetPictureParams(VideoPicture* pVideoPicture)
853 {
854   if (!GetPictureCommon(pVideoPicture))
855     return false;
856 
857   pVideoPicture->iFlags |= m_pFrame->data[0] ? 0 : DVP_FLAG_DROPPED;
858 
859   if (pVideoPicture->videoBuffer)
860     pVideoPicture->videoBuffer->Release();
861   pVideoPicture->videoBuffer = nullptr;
862 
863   CVideoBufferFFmpeg *buffer = dynamic_cast<CVideoBufferFFmpeg*>(m_videoBufferPool->Get());
864   buffer->SetRef(m_pFrame);
865   pVideoPicture->videoBuffer = buffer;
866 
867   if (m_processInfo.GetVideoSettings().m_PostProcess)
868   {
869     m_postProc.SetType(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoPPFFmpegPostProc, false);
870     m_postProc.Process(pVideoPicture);
871   }
872 
873   return true;
874 }
875 
Reset()876 void CDVDVideoCodecFFmpeg::Reset()
877 {
878   m_started = false;
879   m_startedInput = false;
880   m_interlaced = false;
881   m_decoderPts = DVD_NOPTS_VALUE;
882   m_skippedDeint = 0;
883   m_droppedFrames = 0;
884   m_eof = false;
885   m_iLastKeyframe = m_pCodecContext->has_b_frames;
886   avcodec_flush_buffers(m_pCodecContext);
887   av_frame_unref(m_pFrame);
888 
889   if (m_pHardware)
890     m_pHardware->Reset();
891 
892   m_filters = "";
893   FilterClose();
894   m_dropCtrl.Reset(false);
895 }
896 
Reopen()897 void CDVDVideoCodecFFmpeg::Reopen()
898 {
899   Dispose();
900   if (!Open(m_hints, m_options))
901   {
902     Dispose();
903   }
904 }
905 
GetPictureCommon(VideoPicture * pVideoPicture)906 bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture)
907 {
908   if (!m_pFrame)
909     return false;
910 
911   pVideoPicture->iWidth = m_pFrame->width;
912   pVideoPicture->iHeight = m_pFrame->height;
913 
914   /* crop of 10 pixels if demuxer asked it */
915   if(m_pCodecContext->coded_width  && m_pCodecContext->coded_width  < (int)pVideoPicture->iWidth
916                                    && m_pCodecContext->coded_width  > (int)pVideoPicture->iWidth  - 10)
917     pVideoPicture->iWidth = m_pCodecContext->coded_width;
918 
919   if(m_pCodecContext->coded_height && m_pCodecContext->coded_height < (int)pVideoPicture->iHeight
920                                    && m_pCodecContext->coded_height > (int)pVideoPicture->iHeight - 10)
921     pVideoPicture->iHeight = m_pCodecContext->coded_height;
922 
923   double aspect_ratio;
924 
925   /* use variable in the frame */
926   AVRational pixel_aspect = m_pFrame->sample_aspect_ratio;
927 
928   if (pixel_aspect.num == 0)
929     aspect_ratio = 0;
930   else
931     aspect_ratio = av_q2d(pixel_aspect) * pVideoPicture->iWidth / pVideoPicture->iHeight;
932 
933   if (aspect_ratio <= 0.0)
934     aspect_ratio = (float)pVideoPicture->iWidth / (float)pVideoPicture->iHeight;
935 
936   if (m_DAR != aspect_ratio)
937   {
938     m_DAR = aspect_ratio;
939     m_processInfo.SetVideoDAR(static_cast<float>(m_DAR));
940   }
941 
942   /* XXX: we suppose the screen has a 1.0 pixel ratio */ // CDVDVideo will compensate it.
943   pVideoPicture->iDisplayHeight = pVideoPicture->iHeight;
944   pVideoPicture->iDisplayWidth  = ((int)RINT(pVideoPicture->iHeight * aspect_ratio)) & -3;
945   if (pVideoPicture->iDisplayWidth > pVideoPicture->iWidth)
946   {
947     pVideoPicture->iDisplayWidth  = pVideoPicture->iWidth;
948     pVideoPicture->iDisplayHeight = ((int)RINT(pVideoPicture->iWidth / aspect_ratio)) & -3;
949   }
950 
951 
952   pVideoPicture->pts = DVD_NOPTS_VALUE;
953 
954   AVDictionaryEntry * entry = av_dict_get(m_pFrame->metadata, "stereo_mode", NULL, 0);
955   if(entry && entry->value)
956   {
957     pVideoPicture->stereoMode = (const char*)entry->value;
958   }
959   else
960     pVideoPicture->stereoMode.clear();
961 
962   pVideoPicture->iRepeatPicture = 0.5 * m_pFrame->repeat_pict;
963   pVideoPicture->iFlags = 0;
964   pVideoPicture->iFlags |= m_pFrame->interlaced_frame ? DVP_FLAG_INTERLACED : 0;
965   pVideoPicture->iFlags |= m_pFrame->top_field_first ? DVP_FLAG_TOP_FIELD_FIRST: 0;
966 
967   if (m_codecControlFlags & DVD_CODEC_CTRL_DROP)
968   {
969     pVideoPicture->iFlags |= DVP_FLAG_DROPPED;
970   }
971 
972   pVideoPicture->pixelFormat = m_pCodecContext->sw_pix_fmt;
973 
974   pVideoPicture->chroma_position = m_pCodecContext->chroma_sample_location;
975   pVideoPicture->color_primaries = m_pCodecContext->color_primaries == AVCOL_PRI_UNSPECIFIED ? m_hints.colorPrimaries : m_pCodecContext->color_primaries;
976   pVideoPicture->color_transfer = m_pCodecContext->color_trc == AVCOL_TRC_UNSPECIFIED ? m_hints.colorTransferCharacteristic : m_pCodecContext->color_trc;
977   pVideoPicture->color_space = m_pCodecContext->colorspace == AVCOL_SPC_UNSPECIFIED ? m_hints.colorSpace : m_pCodecContext->colorspace;
978   pVideoPicture->colorBits = 8;
979 
980   // determine how number of bits of encoded video
981   if (m_pCodecContext->pix_fmt == AV_PIX_FMT_YUV420P12)
982     pVideoPicture->colorBits = 12;
983   else if (m_pCodecContext->pix_fmt == AV_PIX_FMT_YUV420P10)
984     pVideoPicture->colorBits = 10;
985   else if (m_pCodecContext->codec_id == AV_CODEC_ID_HEVC &&
986            m_pCodecContext->profile == FF_PROFILE_HEVC_MAIN_10)
987     pVideoPicture->colorBits = 10;
988   else if (m_pCodecContext->codec_id == AV_CODEC_ID_H264 &&
989            (m_pCodecContext->profile == FF_PROFILE_H264_HIGH_10||
990             m_pCodecContext->profile == FF_PROFILE_H264_HIGH_10_INTRA))
991     pVideoPicture->colorBits = 10;
992   else if (m_pCodecContext->codec_id == AV_CODEC_ID_VP9 &&
993            (m_pCodecContext->profile == FF_PROFILE_VP9_2 ||
994             m_pCodecContext->profile == FF_PROFILE_VP9_3))
995     pVideoPicture->colorBits = 10;
996 
997   if (m_pCodecContext->color_range == AVCOL_RANGE_JPEG ||
998     m_pCodecContext->pix_fmt == AV_PIX_FMT_YUVJ420P)
999     pVideoPicture->color_range = 1;
1000   else
1001     pVideoPicture->color_range = m_hints.colorRange == AVCOL_RANGE_JPEG ? 1 : 0;
1002 
1003   pVideoPicture->qp_table = av_frame_get_qp_table(m_pFrame,
1004                                                   &pVideoPicture->qstride,
1005                                                   &pVideoPicture->qscale_type);
1006   pVideoPicture->pict_type = m_pFrame->pict_type;
1007 
1008   // metadata
1009   pVideoPicture->hasDisplayMetadata = false;
1010   pVideoPicture->hasLightMetadata = false;
1011   AVFrameSideData *sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
1012   if (sd)
1013   {
1014     pVideoPicture->displayMetadata = *(AVMasteringDisplayMetadata *)sd->data;
1015     pVideoPicture->hasDisplayMetadata = true;
1016   }
1017   else if (m_hints.masteringMetadata)
1018   {
1019     pVideoPicture->displayMetadata = *m_hints.masteringMetadata.get();
1020     pVideoPicture->hasDisplayMetadata = true;
1021   }
1022   sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
1023   if (sd)
1024   {
1025     pVideoPicture->lightMetadata = *(AVContentLightMetadata *)sd->data;
1026     pVideoPicture->hasLightMetadata = true;
1027   }
1028   else if (m_hints.contentLightMetadata)
1029   {
1030     pVideoPicture->lightMetadata = *m_hints.contentLightMetadata.get();
1031     pVideoPicture->hasLightMetadata = true;
1032   }
1033 
1034   if (pVideoPicture->iRepeatPicture)
1035     pVideoPicture->dts = DVD_NOPTS_VALUE;
1036   else
1037     pVideoPicture->dts = m_dts;
1038 
1039   m_dts = DVD_NOPTS_VALUE;
1040 
1041   int64_t bpts = m_pFrame->best_effort_timestamp;
1042   if (bpts != AV_NOPTS_VALUE)
1043   {
1044     pVideoPicture->pts = (double)bpts * DVD_TIME_BASE / AV_TIME_BASE;
1045     if (pVideoPicture->pts == m_decoderPts)
1046     {
1047       pVideoPicture->iRepeatPicture = -0.5;
1048       pVideoPicture->pts = DVD_NOPTS_VALUE;
1049       pVideoPicture->dts = DVD_NOPTS_VALUE;
1050     }
1051   }
1052   else
1053     pVideoPicture->pts = DVD_NOPTS_VALUE;
1054 
1055   if (pVideoPicture->pts != DVD_NOPTS_VALUE)
1056     m_decoderPts = pVideoPicture->pts;
1057 
1058   if (m_requestSkipDeint)
1059   {
1060     pVideoPicture->iFlags |= DVD_CODEC_CTRL_SKIPDEINT;
1061     m_skippedDeint++;
1062   }
1063 
1064   m_requestSkipDeint = false;
1065   pVideoPicture->iFlags |= m_codecControlFlags;
1066 
1067   return true;
1068 }
1069 
FilterOpen(const std::string & filters,bool scale)1070 int CDVDVideoCodecFFmpeg::FilterOpen(const std::string& filters, bool scale)
1071 {
1072   int result;
1073 
1074   if (m_pFilterGraph)
1075     FilterClose();
1076 
1077   if (filters.empty() && !scale)
1078     return 0;
1079 
1080   if (m_pHardware)
1081   {
1082     CLog::Log(LOGWARNING, "CDVDVideoCodecFFmpeg::FilterOpen - skipped opening filters on hardware decode");
1083     return 0;
1084   }
1085 
1086   if (!(m_pFilterGraph = avfilter_graph_alloc()))
1087   {
1088     CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - unable to alloc filter graph");
1089     return -1;
1090   }
1091 
1092   const AVFilter* srcFilter = avfilter_get_by_name("buffer");
1093   const AVFilter* outFilter = avfilter_get_by_name("buffersink"); // should be last filter in the graph for now
1094 
1095   std::string args = StringUtils::Format("%d:%d:%d:%d:%d:%d:%d",
1096                                         m_pCodecContext->width,
1097                                         m_pCodecContext->height,
1098                                         m_pCodecContext->pix_fmt,
1099                                         m_pCodecContext->time_base.num ? m_pCodecContext->time_base.num : 1,
1100                                         m_pCodecContext->time_base.num ? m_pCodecContext->time_base.den : 1,
1101                                         m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.num : 1,
1102                                         m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.den : 1);
1103 
1104   if ((result = avfilter_graph_create_filter(&m_pFilterIn, srcFilter, "src", args.c_str(), NULL, m_pFilterGraph)) < 0)
1105   {
1106     CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_graph_create_filter: src");
1107     return result;
1108   }
1109 
1110   if ((result = avfilter_graph_create_filter(&m_pFilterOut, outFilter, "out", NULL, NULL, m_pFilterGraph)) < 0)
1111   {
1112     CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_graph_create_filter: out");
1113     return result;
1114   }
1115   if ((result = av_opt_set_int_list(m_pFilterOut, "pix_fmts", &m_formats[0],  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
1116   {
1117     CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - failed settings pix formats");
1118     return result;
1119   }
1120 
1121   if (!filters.empty())
1122   {
1123     AVFilterInOut* outputs = avfilter_inout_alloc();
1124     AVFilterInOut* inputs  = avfilter_inout_alloc();
1125 
1126     outputs->name = av_strdup("in");
1127     outputs->filter_ctx = m_pFilterIn;
1128     outputs->pad_idx = 0;
1129     outputs->next = nullptr;
1130 
1131     inputs->name = av_strdup("out");
1132     inputs->filter_ctx = m_pFilterOut;
1133     inputs->pad_idx = 0;
1134     inputs->next = nullptr;
1135 
1136     result = avfilter_graph_parse_ptr(m_pFilterGraph, m_filters.c_str(), &inputs, &outputs, NULL);
1137     avfilter_inout_free(&outputs);
1138     avfilter_inout_free(&inputs);
1139 
1140     if (result < 0)
1141     {
1142       CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_graph_parse");
1143       return result;
1144     }
1145 
1146     if (filters.compare(0,5,"yadif") == 0)
1147     {
1148       m_processInfo.SetVideoDeintMethod(filters);
1149     }
1150     else
1151     {
1152       m_processInfo.SetVideoDeintMethod("none");
1153     }
1154   }
1155   else
1156   {
1157     if ((result = avfilter_link(m_pFilterIn, 0, m_pFilterOut, 0)) < 0)
1158     {
1159       CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_link");
1160       return result;
1161     }
1162 
1163     m_processInfo.SetVideoDeintMethod("none");
1164   }
1165 
1166   if ((result = avfilter_graph_config(m_pFilterGraph,  nullptr)) < 0)
1167   {
1168     CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_graph_config");
1169     return result;
1170   }
1171 
1172   if (CServiceBroker::GetLogging().CanLogComponent(LOGVIDEO))
1173   {
1174     char* graphDump = avfilter_graph_dump(m_pFilterGraph, nullptr);
1175     if (graphDump)
1176     {
1177       CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg::FilterOpen - Final filter graph:\n%s", graphDump);
1178       av_freep(&graphDump);
1179     }
1180   }
1181 
1182   m_filterEof = false;
1183   return result;
1184 }
1185 
FilterClose()1186 void CDVDVideoCodecFFmpeg::FilterClose()
1187 {
1188   if (m_pFilterGraph)
1189   {
1190     CLog::Log(LOGDEBUG, LOGVIDEO, "CDVDVideoCodecFFmpeg::FilterClose - Freeing filter graph");
1191     avfilter_graph_free(&m_pFilterGraph);
1192 
1193     // Disposed by above code
1194     m_pFilterIn = nullptr;
1195     m_pFilterOut = nullptr;
1196   }
1197 }
1198 
FilterProcess(AVFrame * frame)1199 CDVDVideoCodec::VCReturn CDVDVideoCodecFFmpeg::FilterProcess(AVFrame* frame)
1200 {
1201   int result;
1202 
1203   if (frame || (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN))
1204   {
1205     result = av_buffersrc_add_frame(m_pFilterIn, frame);
1206     if (result < 0)
1207     {
1208       CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterProcess - av_buffersrc_add_frame");
1209       return VC_ERROR;
1210     }
1211   }
1212 
1213   result = av_buffersink_get_frame(m_pFilterOut, m_pFilterFrame);
1214 
1215   if (result  == AVERROR(EAGAIN))
1216     return VC_BUFFER;
1217   else if (result == AVERROR_EOF)
1218   {
1219     result = av_buffersink_get_frame(m_pFilterOut, m_pFilterFrame);
1220     m_filterEof = true;
1221     if (result < 0)
1222       return VC_BUFFER;
1223   }
1224   else if (result < 0)
1225   {
1226     CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterProcess - av_buffersink_get_frame");
1227     return VC_ERROR;
1228   }
1229 
1230   av_frame_unref(m_pFrame);
1231   av_frame_move_ref(m_pFrame, m_pFilterFrame);
1232 
1233   return VC_PICTURE;
1234 }
1235 
GetConvergeCount()1236 unsigned CDVDVideoCodecFFmpeg::GetConvergeCount()
1237 {
1238   return m_iLastKeyframe;
1239 }
1240 
GetAllowedReferences()1241 unsigned CDVDVideoCodecFFmpeg::GetAllowedReferences()
1242 {
1243   if(m_pHardware)
1244     return m_pHardware->GetAllowedReferences();
1245   else
1246     return 0;
1247 }
1248 
GetCodecStats(double & pts,int & droppedFrames,int & skippedPics)1249 bool CDVDVideoCodecFFmpeg::GetCodecStats(double &pts, int &droppedFrames, int &skippedPics)
1250 {
1251   if (m_decoderPts != DVD_NOPTS_VALUE)
1252     pts = m_decoderPts;
1253   else
1254     pts = m_dts;
1255 
1256   if (m_droppedFrames)
1257     droppedFrames = m_droppedFrames;
1258   else
1259     droppedFrames = -1;
1260   m_droppedFrames = 0;
1261 
1262   if (m_skippedDeint)
1263     skippedPics = m_skippedDeint;
1264   else
1265     skippedPics = -1;
1266   m_skippedDeint = 0;
1267 
1268   return true;
1269 }
1270 
SetCodecControl(int flags)1271 void CDVDVideoCodecFFmpeg::SetCodecControl(int flags)
1272 {
1273   m_codecControlFlags = flags;
1274 
1275   if (m_pCodecContext)
1276   {
1277     bool bDrop = (flags & DVD_CODEC_CTRL_DROP_ANY) != 0;
1278     if (bDrop && m_pHardware && m_pHardware->CanSkipDeint())
1279     {
1280       m_requestSkipDeint = true;
1281       bDrop = false;
1282     }
1283     else
1284       m_requestSkipDeint = false;
1285 
1286     if (bDrop)
1287     {
1288       m_pCodecContext->skip_frame = AVDISCARD_NONREF;
1289       m_pCodecContext->skip_idct = AVDISCARD_NONREF;
1290       m_pCodecContext->skip_loop_filter = AVDISCARD_NONREF;
1291     }
1292     else
1293     {
1294       m_pCodecContext->skip_frame = AVDISCARD_DEFAULT;
1295       m_pCodecContext->skip_idct = AVDISCARD_DEFAULT;
1296       m_pCodecContext->skip_loop_filter = AVDISCARD_DEFAULT;
1297     }
1298   }
1299 
1300   if (m_pHardware)
1301     m_pHardware->SetCodecControl(flags);
1302 }
1303 
SetHardware(IHardwareDecoder * hardware)1304 void CDVDVideoCodecFFmpeg::SetHardware(IHardwareDecoder* hardware)
1305 {
1306   SAFE_RELEASE(m_pHardware);
1307   m_pHardware = hardware;
1308   UpdateName();
1309 }
1310 
GetHWAccel()1311 IHardwareDecoder* CDVDVideoCodecFFmpeg::GetHWAccel()
1312 {
1313   return m_pHardware;
1314 }
1315 
1316