backport 569648f2a3b8e094c33d102edd41397ca04b07be into dharma 10.1 (because git maste...
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / DVDVideoCodecFFmpeg.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "system.h"
23 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
24   #include "config.h"
25 #endif
26 #include "DVDVideoCodecFFmpeg.h"
27 #include "DVDDemuxers/DVDDemux.h"
28 #include "DVDStreamInfo.h"
29 #include "DVDClock.h"
30 #include "DVDCodecs/DVDCodecs.h"
31 #include "../../../../utils/Win32Exception.h"
32 #if defined(_LINUX) || defined(_WIN32)
33 #include "utils/CPUInfo.h"
34 #endif
35 #include "AdvancedSettings.h"
36 #include "GUISettings.h"
37 #include "utils/log.h"
38 #include "boost/shared_ptr.hpp"
39
40 #ifndef _LINUX
41 #define RINT(x) ((x) >= 0 ? ((int)((x) + 0.5)) : ((int)((x) - 0.5)))
42 #else
43 #include <math.h>
44 #define RINT lrint
45 #endif
46
47 #include "cores/VideoRenderers/RenderManager.h"
48
49 #ifdef HAVE_LIBVDPAU
50 #include "VDPAU.h"
51 #endif
52 #ifdef HAS_DX
53 #include "DXVA.h"
54 #endif
55 #ifdef HAVE_LIBVA
56 #include "VAAPI.h"
57 #endif
58
59 using namespace boost;
60
61 enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx
62                                                 , const PixelFormat * fmt )
63 {
64   CDVDVideoCodecFFmpeg* ctx  = (CDVDVideoCodecFFmpeg*)avctx->opaque;
65
66   if(!ctx->IsHardwareAllowed())
67     return ctx->m_dllAvCodec.avcodec_default_get_format(avctx, fmt);
68
69   const PixelFormat * cur = fmt;
70   while(*cur != PIX_FMT_NONE)
71   {
72 #ifdef HAVE_LIBVDPAU
73     if(CVDPAU::IsVDPAUFormat(*cur) && g_guiSettings.GetBool("videoplayer.usevdpau"))
74     {
75       if(ctx->GetHardware())
76         return *cur;
77         
78       CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height);
79       CVDPAU* vdp = new CVDPAU();
80       if(vdp->Open(avctx, *cur))
81       {
82         ctx->SetHardware(vdp);
83         return *cur;
84       }
85       else
86         vdp->Release();
87     }
88 #endif
89 #ifdef HAS_DX
90   if(DXVA::CDecoder::Supports(*cur) && g_guiSettings.GetBool("videoplayer.usedxva2"))
91   {
92     DXVA::CDecoder* dec = new DXVA::CDecoder();
93     if(dec->Open(avctx, *cur))
94     {
95       ctx->SetHardware(dec);
96       return *cur;
97     }
98     else
99       dec->Release();
100   }
101 #endif
102 #ifdef HAVE_LIBVA
103     if(*cur == PIX_FMT_VAAPI_VLD && g_guiSettings.GetBool("videoplayer.usevaapi"))
104     {
105       VAAPI::CDecoder* dec = new VAAPI::CDecoder();
106       if(dec->Open(avctx, *cur))
107       {
108         ctx->SetHardware(dec);
109         return *cur;
110       }
111       else
112         dec->Release();      
113     }
114 #endif
115     cur++;
116   }
117   return ctx->m_dllAvCodec.avcodec_default_get_format(avctx, fmt);
118 }
119
120
121 CDVDVideoCodecFFmpeg::IHardwareDecoder*  CDVDVideoCodecFFmpeg::IHardwareDecoder::Acquire()
122 {
123   InterlockedIncrement(&m_references);
124   return this;
125 }
126
127 long CDVDVideoCodecFFmpeg::IHardwareDecoder::Release()
128 {
129   long count = InterlockedDecrement(&m_references);
130   ASSERT(count >= 0);
131   if (count == 0) delete this;
132   return count;
133 }
134
135 CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec()
136 {
137   m_pCodecContext = NULL;
138   m_pConvertFrame = NULL;
139   m_pFrame = NULL;
140
141   m_iPictureWidth = 0;
142   m_iPictureHeight = 0;
143
144   m_iScreenWidth = 0;
145   m_iScreenHeight = 0;
146   m_bSoftware = false;
147   m_pHardware = NULL;
148   m_iLastKeyframe = 0;
149   m_dts = DVD_NOPTS_VALUE;
150   m_started = false;
151 }
152
153 CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg()
154 {
155   Dispose();
156 }
157
158 bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
159 {
160   AVCodec* pCodec;
161
162   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwScale.Load()) return false;
163
164   m_dllAvCodec.avcodec_register_all();
165
166   #if (! defined USE_EXTERNAL_FFMPEG)
167     m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
168   #elif (defined HAVE_LIBSWSCALE_RGB2RGB_H) || (defined HAVE_FFMPEG_RGB2RGB_H)
169     m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
170   #endif
171
172   m_bSoftware     = hints.software;
173   m_pCodecContext = m_dllAvCodec.avcodec_alloc_context();
174
175   pCodec = NULL;
176
177 #ifdef HAVE_LIBVDPAU
178   if(g_guiSettings.GetBool("videoplayer.usevdpau") && !m_bSoftware)
179   {
180     while((pCodec = m_dllAvCodec.av_codec_next(pCodec)))
181     {
182       if(pCodec->id == hints.codec
183       && pCodec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
184       {
185         if ((pCodec->id == CODEC_ID_MPEG4 || pCodec->id == CODEC_ID_XVID) && !g_advancedSettings.m_videoAllowMpeg4VDPAU)
186           continue;
187
188         CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Creating VDPAU(%ix%i, %d)",hints.width, hints.height, hints.codec);
189         CVDPAU* vdp = new CVDPAU();
190         m_pCodecContext->codec_id = hints.codec;
191         m_pCodecContext->width    = hints.width;
192         m_pCodecContext->height   = hints.height;
193         if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE))
194         {
195           m_pHardware = vdp;
196           m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set
197           break;
198         }
199         m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set
200         CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Failed to get VDPAU device");
201         vdp->Release();
202       }
203     }
204   }
205 #endif
206
207   if(pCodec == NULL)
208     pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);
209
210   if(pCodec == NULL)
211   {
212     CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
213     return false;
214   }
215
216   CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Using codec: %s",pCodec->long_name ? pCodec->long_name : pCodec->name);
217
218   m_pCodecContext->opaque = (void*)this;
219   m_pCodecContext->debug_mv = 0;
220   m_pCodecContext->debug = 0;
221   m_pCodecContext->workaround_bugs = FF_BUG_AUTODETECT;
222   m_pCodecContext->get_format = GetFormat;
223   m_pCodecContext->codec_tag = hints.codec_tag;
224
225   if (pCodec->id != CODEC_ID_H264 && pCodec->capabilities & CODEC_CAP_DR1
226 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,69,0)
227       && pCodec->id != CODEC_ID_VP8
228 #endif
229      )
230     m_pCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
231
232   // if we don't do this, then some codecs seem to fail.
233   m_pCodecContext->coded_height = hints.height;
234   m_pCodecContext->coded_width = hints.width;
235
236   if( hints.extradata && hints.extrasize > 0 )
237   {
238     m_pCodecContext->extradata_size = hints.extrasize;
239     m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
240     memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
241   }
242
243   // set acceleration
244   m_pCodecContext->dsp_mask = 0;//FF_MM_FORCE | FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE;
245
246   // advanced setting override for skip loop filter (see avcodec.h for valid options)
247   // TODO: allow per video setting?
248   if (g_advancedSettings.m_iSkipLoopFilter != 0)
249   {
250     m_pCodecContext->skip_loop_filter = (AVDiscard)g_advancedSettings.m_iSkipLoopFilter;
251   }
252
253   // set any special options
254   for(CDVDCodecOptions::iterator it = options.begin(); it != options.end(); it++)
255   {
256     m_dllAvCodec.av_set_string(m_pCodecContext, it->m_name.c_str(), it->m_value.c_str());
257   }
258
259 #if defined(_LINUX) || defined(_WIN32)
260   int num_threads = std::min(8 /*MAX_THREADS*/, g_cpuInfo.getCPUCount());
261   if( num_threads > 1 && !hints.software && m_pHardware == NULL // thumbnail extraction fails when run threaded
262   && ( pCodec->id == CODEC_ID_H264
263     || pCodec->id == CODEC_ID_MPEG4 ))
264     m_dllAvCodec.avcodec_thread_init(m_pCodecContext, num_threads);
265 #endif
266
267   if (m_dllAvCodec.avcodec_open(m_pCodecContext, pCodec) < 0)
268   {
269     CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to open codec");
270     return false;
271   }
272
273   m_pFrame = m_dllAvCodec.avcodec_alloc_frame();
274   if (!m_pFrame) return false;
275
276   if(pCodec->name)
277     m_name = CStdString("ff-") + pCodec->name;
278   else
279     m_name = "ffmpeg";
280
281   if(m_pHardware)
282     m_name += "-" + m_pHardware->Name();
283
284   return true;
285 }
286
287 void CDVDVideoCodecFFmpeg::Dispose()
288 {
289   if (m_pFrame) m_dllAvUtil.av_free(m_pFrame);
290   m_pFrame = NULL;
291
292   if (m_pConvertFrame)
293   {
294     m_dllAvCodec.avpicture_free(m_pConvertFrame);
295     m_dllAvUtil.av_free(m_pConvertFrame);
296   }
297   m_pConvertFrame = NULL;
298
299   if (m_pCodecContext)
300   {
301     if (m_pCodecContext->codec) m_dllAvCodec.avcodec_close(m_pCodecContext);
302     if (m_pCodecContext->extradata)
303     {
304       m_dllAvUtil.av_free(m_pCodecContext->extradata);
305       m_pCodecContext->extradata = NULL;
306       m_pCodecContext->extradata_size = 0;
307     }
308     m_dllAvUtil.av_free(m_pCodecContext);
309     m_pCodecContext = NULL;
310   }
311   SAFE_RELEASE(m_pHardware);
312
313   m_dllAvCodec.Unload();
314   m_dllAvUtil.Unload();
315 }
316
317 void CDVDVideoCodecFFmpeg::SetDropState(bool bDrop)
318 {
319   if( m_pCodecContext )
320   {
321     // i don't know exactly how high this should be set
322     // couldn't find any good docs on it. think it varies
323     // from codec to codec on what it does
324
325     //  2 seem to be to high.. it causes video to be ruined on following images
326     if( bDrop )
327     {
328       // TODO: 'hurry_up' has been deprecated in favor of the skip_* variables
329       // Use those instead.
330
331       m_pCodecContext->hurry_up = 1;
332       //m_pCodecContext->skip_frame = AVDISCARD_NONREF;
333       //m_pCodecContext->skip_idct = AVDISCARD_NONREF;
334       //m_pCodecContext->skip_loop_filter = AVDISCARD_NONREF;
335     }
336     else
337     {
338       m_pCodecContext->hurry_up = 0;
339       //m_pCodecContext->skip_frame = AVDISCARD_DEFAULT;
340       //m_pCodecContext->skip_idct = AVDISCARD_DEFAULT;
341       //m_pCodecContext->skip_loop_filter = AVDISCARD_DEFAULT;
342     }
343   }
344 }
345
346 union pts_union
347 {
348   double  pts_d;
349   int64_t pts_i;
350 };
351
352 static int64_t pts_dtoi(double pts)
353 {
354   pts_union u;
355   u.pts_d = pts;
356   return u.pts_i;
357 }
358
359 static double pts_itod(int64_t pts)
360 {
361   pts_union u;
362   u.pts_i = pts;
363   return u.pts_d;
364 }
365
366 int CDVDVideoCodecFFmpeg::Decode(BYTE* pData, int iSize, double dts, double pts)
367 {
368   int iGotPicture = 0, len = 0;
369
370   if (!m_pCodecContext)
371     return VC_ERROR;
372
373   if(pData)
374     m_iLastKeyframe++;
375
376   shared_ptr<CSingleLock> lock;
377   if(m_pHardware)
378   {
379     CCriticalSection* section = m_pHardware->Section();
380     if(section)
381       lock = shared_ptr<CSingleLock>(new CSingleLock(*section));
382
383     int result;
384     if(pData)
385       result = m_pHardware->Check(m_pCodecContext);
386     else
387       result = m_pHardware->Decode(m_pCodecContext, NULL);
388
389     if(result)
390       return result;
391   }
392
393   m_dts = dts;
394   m_pCodecContext->reordered_opaque = pts_dtoi(pts);
395
396   len = m_dllAvCodec.avcodec_decode_video(m_pCodecContext, m_pFrame, &iGotPicture, pData, iSize);
397
398   if(m_iLastKeyframe < m_pCodecContext->has_b_frames + 1)
399     m_iLastKeyframe = m_pCodecContext->has_b_frames + 1;
400
401   if (len < 0)
402   {
403     CLog::Log(LOGERROR, "%s - avcodec_decode_video returned failure", __FUNCTION__);
404     return VC_ERROR;
405   }
406
407   if (len != iSize && !m_pCodecContext->hurry_up)
408     CLog::Log(LOGWARNING, "%s - avcodec_decode_video didn't consume the full packet. size: %d, consumed: %d", __FUNCTION__, iSize, len);
409
410   if (!iGotPicture)
411     return VC_BUFFER;
412
413   if(m_pFrame->key_frame)
414   {
415     m_started = true;
416     m_iLastKeyframe = m_pCodecContext->has_b_frames + 1;
417   }
418
419   if(m_pCodecContext->pix_fmt != PIX_FMT_YUV420P
420   && m_pCodecContext->pix_fmt != PIX_FMT_YUVJ420P
421   && m_pHardware == NULL)
422   {
423     if (!m_dllSwScale.IsLoaded())
424     {
425       if(!m_dllSwScale.Load())
426         return VC_ERROR;
427
428         #if (! defined USE_EXTERNAL_FFMPEG)
429           m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
430         #elif (defined HAVE_LIBSWSCALE_RGB2RGB_H) || (defined HAVE_FFMPEG_RGB2RGB_H)
431           m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
432         #endif
433     }
434
435     if (!m_pConvertFrame)
436     {
437       // Allocate an AVFrame structure
438       m_pConvertFrame = (AVPicture*)m_dllAvUtil.av_mallocz(sizeof(AVPicture));
439       // Due to a bug in swsscale we need to allocate one extra line of data
440       if(m_dllAvCodec.avpicture_alloc( m_pConvertFrame
441                                      , PIX_FMT_YUV420P
442                                      , m_pCodecContext->width
443                                      , m_pCodecContext->height+1) < 0)
444       {
445         m_dllAvUtil.av_free(m_pConvertFrame);
446         m_pConvertFrame = NULL;
447         return VC_ERROR;
448       }
449     }
450
451     // convert the picture
452     struct SwsContext *context = m_dllSwScale.sws_getContext(m_pCodecContext->width, m_pCodecContext->height,
453                                          m_pCodecContext->pix_fmt, m_pCodecContext->width, m_pCodecContext->height,
454                                          PIX_FMT_YUV420P, SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
455
456     if(context == NULL)
457     {
458       CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::Decode - unable to obtain sws context for w:%i, h:%i, pixfmt: %i", m_pCodecContext->width, m_pCodecContext->height, m_pCodecContext->pix_fmt);
459       return VC_ERROR;
460     }
461
462     m_dllSwScale.sws_scale(context
463                           , m_pFrame->data
464                           , m_pFrame->linesize
465                           , 0
466                           , m_pCodecContext->height
467                           , m_pConvertFrame->data
468                           , m_pConvertFrame->linesize);
469
470     m_dllSwScale.sws_freeContext(context);
471   }
472   else
473   {
474     // no need to convert, just free any existing convert buffers
475     if (m_pConvertFrame)
476     {
477       m_dllAvCodec.avpicture_free(m_pConvertFrame);
478       m_dllAvUtil.av_free(m_pConvertFrame);
479       m_pConvertFrame = NULL;
480     }
481   }
482
483   int result;
484   if(m_pHardware)
485     result = m_pHardware->Decode(m_pCodecContext, m_pFrame);
486   else
487     result = VC_PICTURE | VC_BUFFER;
488
489   if(result & VC_FLUSHED)
490     Reset();
491
492   return result;
493 }
494
495 void CDVDVideoCodecFFmpeg::Reset()
496 {
497   m_started = false;
498   m_iLastKeyframe = m_pCodecContext->has_b_frames;
499   m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
500
501   if (m_pConvertFrame)
502   {
503     delete[] m_pConvertFrame->data[0];
504     m_dllAvUtil.av_free(m_pConvertFrame);
505     m_pConvertFrame = NULL;
506   }
507 }
508
509 bool CDVDVideoCodecFFmpeg::GetPicture(DVDVideoPicture* pDvdVideoPicture)
510 {
511   GetVideoAspect(m_pCodecContext, pDvdVideoPicture->iDisplayWidth, pDvdVideoPicture->iDisplayHeight);
512
513   if(m_pCodecContext->coded_width  && m_pCodecContext->coded_width  < m_pCodecContext->width
514                                    && m_pCodecContext->coded_width  > m_pCodecContext->width  - 10)
515     pDvdVideoPicture->iWidth = m_pCodecContext->coded_width;
516   else
517     pDvdVideoPicture->iWidth = m_pCodecContext->width;
518
519   if(m_pCodecContext->coded_height && m_pCodecContext->coded_height < m_pCodecContext->height
520                                    && m_pCodecContext->coded_height > m_pCodecContext->height - 10)
521     pDvdVideoPicture->iHeight = m_pCodecContext->coded_height;
522   else
523     pDvdVideoPicture->iHeight = m_pCodecContext->height;
524
525   pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
526
527   // if we have a converted frame, use that
528   AVFrame *frame = m_pFrame;
529
530   if (!frame)
531     return false;
532
533   pDvdVideoPicture->iRepeatPicture = 0.5 * frame->repeat_pict;
534   pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
535   pDvdVideoPicture->iFlags |= frame->interlaced_frame ? DVP_FLAG_INTERLACED : 0;
536   pDvdVideoPicture->iFlags |= frame->top_field_first ? DVP_FLAG_TOP_FIELD_FIRST: 0;
537   if(m_pCodecContext->pix_fmt == PIX_FMT_YUVJ420P)
538     pDvdVideoPicture->color_range = 1;
539
540   pDvdVideoPicture->qscale_table = frame->qscale_table;
541   pDvdVideoPicture->qscale_stride = frame->qstride;
542
543   switch (frame->qscale_type) {
544   case FF_QSCALE_TYPE_MPEG1:
545     pDvdVideoPicture->qscale_type = DVP_QSCALE_MPEG1;
546     break;
547   case FF_QSCALE_TYPE_MPEG2:
548     pDvdVideoPicture->qscale_type = DVP_QSCALE_MPEG2;
549     break;
550   case FF_QSCALE_TYPE_H264:
551     pDvdVideoPicture->qscale_type = DVP_QSCALE_H264;
552     break;
553   default:
554     pDvdVideoPicture->qscale_type = DVP_QSCALE_UNKNOWN;
555   }
556
557   pDvdVideoPicture->dts = m_dts;
558   m_dts = DVD_NOPTS_VALUE;
559   if (frame->reordered_opaque)
560     pDvdVideoPicture->pts = pts_itod(frame->reordered_opaque);
561   else
562     pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
563
564   if(!m_started)
565     pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
566
567   if(m_pHardware)
568     return m_pHardware->GetPicture(m_pCodecContext, m_pFrame, pDvdVideoPicture);
569
570   if(m_pConvertFrame)
571   {
572     for (int i = 0; i < 4; i++)
573       pDvdVideoPicture->data[i]      = m_pConvertFrame->data[i];
574     for (int i = 0; i < 4; i++)
575       pDvdVideoPicture->iLineSize[i] = m_pConvertFrame->linesize[i];
576   }
577   else
578   {
579     for (int i = 0; i < 4; i++)
580       pDvdVideoPicture->data[i]      = frame->data[i];
581     for (int i = 0; i < 4; i++)
582       pDvdVideoPicture->iLineSize[i] = frame->linesize[i];
583   }
584
585   pDvdVideoPicture->iFlags |= pDvdVideoPicture->data[0] ? 0 : DVP_FLAG_DROPPED;
586   pDvdVideoPicture->format = DVDVideoPicture::FMT_YUV420P;
587
588   return true;
589 }
590
591 /*
592  * Calculate the height and width this video should be displayed in
593  */
594 void CDVDVideoCodecFFmpeg::GetVideoAspect(AVCodecContext* pCodecContext, unsigned int& iWidth, unsigned int& iHeight)
595 {
596   double aspect_ratio;
597
598   /* XXX: use variable in the frame */
599   if (pCodecContext->sample_aspect_ratio.num == 0) aspect_ratio = 0;
600   else aspect_ratio = av_q2d(pCodecContext->sample_aspect_ratio) * pCodecContext->width / pCodecContext->height;
601
602   if (aspect_ratio <= 0.0) aspect_ratio = (float)pCodecContext->width / (float)pCodecContext->height;
603
604   /* XXX: we suppose the screen has a 1.0 pixel ratio */ // CDVDVideo will compensate it.
605   iHeight = pCodecContext->height;
606   iWidth = ((int)RINT(pCodecContext->height * aspect_ratio)) & -3;
607   if (iWidth > (unsigned int)pCodecContext->width)
608   {
609     iWidth = pCodecContext->width;
610     iHeight = ((int)RINT(pCodecContext->width / aspect_ratio)) & -3;
611   }
612 }
613
614 unsigned CDVDVideoCodecFFmpeg::GetConvergeCount()
615 {
616   if(m_pHardware)
617     return m_iLastKeyframe;
618   else
619     return 0;
620 }