svvitch
digital signage player
|
00001 #ifdef USE_FFMPEG 00002 00003 #include "FFMovieContent.h" 00004 #include "Utils.h" 00005 00006 00007 FFMovieContent::FFMovieContent(Renderer& renderer, int splitType): 00008 Content(renderer, splitType), _ic(NULL), _fps(0), _audioDecoder(NULL), _videoDecoder(NULL), _vf(NULL), _prepareVF(NULL), 00009 _starting(false), _frameOddEven(0), _finished(true), _seeking(false) 00010 { 00011 initialize(); 00012 } 00013 00014 FFMovieContent::‾FFMovieContent() { 00015 Poco::ScopedLock<Poco::FastMutex> lock(_openLock); 00016 initialize(); 00017 } 00018 00019 00020 void FFMovieContent::initialize() { 00021 close(); 00022 _fpsCounter.start(); 00023 _avgTime = 0; 00024 if (_vf) { 00025 Poco::ScopedLock<Poco::FastMutex> lock(_frameLock); 00026 SAFE_DELETE(_vf); 00027 } 00028 } 00029 00031 bool FFMovieContent::open(const MediaItemPtr media, const int offset) { 00032 Poco::ScopedLock<Poco::FastMutex> lock(_openLock); 00033 initialize(); 00034 00035 if (media->files().empty() || media->files().size() <= offset) return false; 00036 MediaItemFile mif = media->files()[offset]; 00037 //for (vector<MediaItemFile>::const_iterator it = media->files().begin(); it != media->files().end(); it++) { 00038 // switch (it->type()) { 00039 // case MediaTypeMovie: 00040 // mif = *it; 00041 // break; 00042 // } 00043 //} 00044 00045 AVInputFormat* format = NULL; 00046 if (mif.file().find(string("vfwcap")) == 0) { 00047 _log.information(Poco::format("capture device: %s", mif.file())); 00048 format = av_find_input_format("vfwcap"); 00049 if (format) _log.information(Poco::format("input format: %s", string(format->long_name))); 00050 // AVOutputFormat* outf = guess_format("vfwcap", mbfile.c_str(), NULL); 00051 // if (outf) _log.information(Poco::format("output format: [%s]", string(outf->long_name))); 00052 00053 AVFormatParameters ap = {0}; 00054 // ap.prealloced_context = 1; 00055 ap.width = 640; 00056 ap.height = 480; 00057 ap.pix_fmt = PIX_FMT_RGB24; //PIX_FMT_NONE; 00058 ap.time_base.num = 1; 00059 ap.time_base.den = 30; 00060 ap.channel = 0; 00061 // ap.standard = NULL; 00062 // ap.video_codec_id = CODEC_ID_NONE; 00063 // ap.audio_codec_id = CODEC_ID_NONE; 00064 00065 // ap->sample_rate = audio_sample_rate; 00066 // ap->channels = audio_channels; 00067 // ap->time_base.den = frame_rate.num; 00068 // ap->time_base.num = frame_rate.den; 00069 // ap->width = frame_width + frame_padleft + frame_padright; 00070 // ap->height = frame_height + frame_padtop + frame_padbottom; 00071 // ap->pix_fmt = frame_pix_fmt; 00072 // ap->sample_fmt = audio_sample_fmt; //FIXME:not implemented in libavformat 00073 // ap->channel = video_channel; 00074 // ap->standard = video_standard; 00075 // ap->video_codec_id = find_codec_or_die(video_codec_name, CODEC_TYPE_VIDEO, 0); 00076 // ap->audio_codec_id = find_codec_or_die(audio_codec_name, CODEC_TYPE_AUDIO, 0); 00077 00078 if (av_open_input_file(&_ic, mif.file().substr(6).c_str(), format, 0, &ap) != 0) { 00079 _log.warning(Poco::format("failed open capture device: [%s]", mif.file())); 00080 return false; 00081 } 00082 } else { 00083 string file = Path(config().dataRoot, Path(mif.file())).absolute().toString(); 00084 string mbfile; 00085 svvitch::utf8_sjis(file, mbfile); 00086 if (av_open_input_file(&_ic, mbfile.c_str(), format, 0,NULL) != 0) { 00087 _log.warning(Poco::format("failed open file: [%s]", file)); 00088 return false; 00089 } 00090 } 00091 // _log.information(Poco::format("opened: %s", file)); 00092 00093 if (av_find_stream_info(_ic) < 0 || !_ic) { 00094 _log.warning(Poco::format("failed find stream info: %s", mif.file())); 00095 close(); 00096 return false; 00097 } 00098 int64_t start = media->start() / F(1000) * AV_TIME_BASE; 00099 if (media->start() > 0 && av_seek_frame(_ic, -1, start, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME) != 0) { 00100 _log.warning(Poco::format("failed set start time: %d", media->start())); 00101 close(); 00102 return false; 00103 } 00104 00105 //_log.information(Poco::format("find stream information: %s streams: %u", string(_ic->title), _ic->nb_streams)); 00106 for (int i = 0; i < _ic->nb_streams; i++) { 00107 AVStream* stream = _ic->streams[i]; 00108 AVCodecContext* avctx = stream->codec; 00109 if (!avctx) { 00110 _log.warning(Poco::format("failed stream codec[%d]: %s", i, mif.file())); 00111 continue; 00112 } 00113 if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { 00114 //IDirectXVideoDecoderService* service = NULL; 00115 //DXVA2CreateVideoService(_renderer.get3DDevice(), IID_PPV_ARGS(&service)); 00116 //UINT resetToken = 0; 00117 //IDirect3DDeviceManager9* d3dManager = NULL; 00118 //HRESULT hr = DXVA2CreateDirect3DDeviceManager9(&resetToken, &d3dManager); 00119 //if SUCCEEDED(hr) { 00120 // hr = d3dManager->ResetDevice(_renderer.get3DDevice(), resetToken); 00121 // if SUCCEEDED(hr) { 00122 // } else { 00123 // _log.warning("failed ResetDevice()"); 00124 // } 00125 //} else { 00126 // _log.warning("failed DXVA2CreateDirect3DDeviceManager9()"); 00127 //} 00128 //SAFE_RELEASE(d3dManager); 00129 00130 //dxva_context* dxva = (dxva_context*)av_malloc(sizeof(dxva_context)); 00131 // AVHWAccel* hwaccel = av_hwaccel_next(NULL); 00132 // if (hwaccel) { 00133 // avctx->hwaccel_context = hwaccel; 00134 // avctx->codec_id = hwaccel->id; 00135 // _log.information(Poco::format("set hardware accelerator: %s %d", string(hwaccel->name), ((int)hwaccel->pix_fmt))); 00136 // } 00137 } 00138 00139 AVCodec* avcodec = avcodec_find_decoder(avctx->codec_id); 00140 if (!avcodec) { 00141 _log.warning(Poco::format("not found decoder[%d]: %s", i, mif.file())); 00142 continue; 00143 } 00144 00145 float rate = 0; 00146 switch (avctx->codec_type) { 00147 case AVMEDIA_TYPE_VIDEO: 00148 { 00149 //string name(avcodec->long_name); 00150 //if (name.find("H.264") != string::npos) { 00151 // AVHWAccel* hwaccel = av_hwaccel_next(NULL); 00152 // if (hwaccel) { 00153 // avctx->hwaccel_context = hwaccel; 00154 // _log.information(Poco::format("set hardware accelerator: %s %d", string(hwaccel->name), ((int)hwaccel->pix_fmt))); 00155 // } 00156 //} 00157 } 00158 if (_video < 0 && avcodec_open(avctx, avcodec) < 0) { 00159 _log.warning(Poco::format("failed open codec: %s", mif.file())); 00160 } else { 00161 // codecがopenできた 00162 float rate = F(stream->r_frame_rate.num) / stream->r_frame_rate.den; 00163 if (rate < 24.5f) { 00164 _fps = 24; 00165 } else if (rate < 26.0f) { 00166 _fps = 25; 00167 } else if (rate < 31.0f) { 00168 _fps = 30; 00169 } else if (rate < 51.0f) { 00170 _fps = (int)rate; 00171 } else { 00172 _fps = 60; 00173 } 00174 if (_fps <= 30) { 00175 _duration = L((stream->duration * F(stream->time_base.num) / stream->time_base.den) * 60); 00176 } else { 00177 _duration = stream->duration * stream->time_base.num * stream->r_frame_rate.num / stream->time_base.den / stream->r_frame_rate.den; 00178 } 00179 00180 _log.information(Poco::format("open decoder: %s %d(%d/%d) %dkbps", string(avcodec->long_name), _fps, stream->r_frame_rate.num, stream->r_frame_rate.den, avctx->bit_rate / 1024)); 00181 _video = i; 00182 _videoDecoder = new FFVideoDecoder(_renderer, _ic, _video); 00183 _videoDecoder->start(); 00184 _w = avctx->width; 00185 _h = avctx->height; 00186 } 00187 break; 00188 00189 case AVMEDIA_TYPE_AUDIO: 00190 if (_renderer.getSoundDevice() && config().splitType != 21) { 00191 if (_audio < 0 && avcodec_open(avctx, avcodec) < 0) { 00192 _log.warning(Poco::format("failed open codec: %s", mif.file())); 00193 } else { 00194 // codecがopenできた 00195 _log.information(Poco::format("open decoder: %s %dkbps", string(avcodec->long_name), avctx->bit_rate / 1024)); 00196 _audio = i; 00197 _audioDecoder = new FFAudioDecoder(_renderer, _ic, _audio); 00198 _audioDecoder->start(); 00199 } 00200 } 00201 break; 00202 } 00203 } 00204 if (_audioDecoder && !_audioDecoder->isReady()) return false; 00205 if (_videoDecoder && !_videoDecoder->isReady()) return false; 00206 00207 _worker = this; 00208 _thread.start(*_worker); 00209 00210 _log.information(Poco::format("opened: %s", mif.file())); 00211 _mediaID = media->id(); 00212 _current = media->start() * 60 / 1000; 00213 if (media->duration() > 0) _duration = media->duration() * 60 / 1000; 00214 set("alpha", 1.0f); 00215 _starting = false; 00216 _finished = false; 00217 return true; 00218 } 00219 00220 void FFMovieContent::run() { 00221 _log.information("movie thread start"); 00222 long count = 0; 00223 AVPacket packet; 00224 while (_worker) { 00225 Poco::Thread::sleep(0); 00226 if (!_playing) { 00227 // 停止中はウェイトを増やし負荷を下げる 00228 Poco::Thread::sleep(50); 00229 } 00230 if (_seeking) { 00231 // シーク中 00232 Poco::Thread::sleep(10); 00233 continue; 00234 } 00235 if (_audioDecoder) { 00236 // audioデコード処理 00237 _audioDecoder->decode(); 00238 _audioDecoder->writeData(); 00239 } 00240 if (_videoDecoder) { 00241 // videoデコード処理 00242 if (_videoDecoder->bufferedPackets() > 200) { 00243 Poco::Thread::sleep(10); 00244 continue; 00245 } 00246 } 00247 00248 if (av_read_frame(_ic, &packet) < 0) { 00249 // パケット終了 or 異常 00250 if (!_finished && _audioDecoder) _audioDecoder->finishedPacket(); 00251 _finished = true; 00252 Poco::Thread::sleep(10); 00253 continue; 00254 } 00255 00256 if (packet.stream_index == _video && _videoDecoder) { 00257 // 映像 00258 _videoDecoder->pushPacket(&packet); 00259 00260 } else if (packet.stream_index == _audio && _audioDecoder) { 00261 // 音声 00262 _audioDecoder->pushPacket(&packet); 00263 00264 } else { 00265 av_free_packet(&packet); 00266 } 00267 count++; 00268 } 00269 _log.information(Poco::format("movie thread end %ldpackets", count)); 00270 } 00271 00275 void FFMovieContent::play() { 00276 _playing = true; 00277 _starting = true; 00278 _playTimer.start(); 00279 } 00280 00281 void FFMovieContent::pause() { 00282 if (_audioDecoder) _audioDecoder->stop(); 00283 } 00284 00288 void FFMovieContent::stop() { 00289 if (_audioDecoder) _audioDecoder->stop(); 00290 _playing = false; 00291 } 00292 00304 const bool FFMovieContent::seek(const int64_t timestamp) { 00305 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00306 _seeking = true; 00307 Poco::Thread::sleep(10); 00308 // if (!_ic || av_seek_frame(_ic, _video, timestamp, 0) < 0) { 00309 if (!_ic || av_seek_frame(_ic, -1, timestamp, 0) < 0) { 00310 _log.warning("failed seek frame"); 00311 return false; 00312 } 00313 _seeking = false; 00314 return true; 00315 } 00316 00317 const bool FFMovieContent::finished() { 00318 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00319 if (_playing) { 00320 if (_finished) { 00321 if (_videoDecoder) { 00322 if (_videoDecoder->bufferedFrames() == 0) { 00323 if (_audioDecoder && _audioDecoder->playing()) _audioDecoder->stop(); 00324 return true; 00325 } 00326 return false; 00327 } 00328 return _mediaID.empty(); 00329 } 00330 } else { 00331 return true; 00332 } 00333 return false; 00334 } 00335 00337 void FFMovieContent::close() { 00338 _mediaID.clear(); 00339 if (_ic) { 00340 stop(); 00341 { 00342 Poco::ScopedLock<Poco::FastMutex> lock(_frameLock); 00343 SAFE_DELETE(_vf); 00344 } 00345 if (_worker) { 00346 _worker = NULL; 00347 _thread.join(); 00348 } 00349 { 00350 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00351 SAFE_DELETE(_audioDecoder); 00352 SAFE_DELETE(_videoDecoder); 00353 // SAFE_DELETE(_vf); // 本来はここが良さそうだがフレーム描画だと落ちるので_videoDecoderが無くなったらdraw()の方でdelete 00354 } 00355 for (int i = 0; i < _ic->nb_streams; i++) { 00356 AVCodecContext* avctx = _ic->streams[i]->codec; 00357 if (avctx) { 00358 if (avctx->codec) { 00359 avcodec_flush_buffers(avctx); 00360 // avcodec_default_free_buffers(avctx); 00361 _log.information(Poco::format("release codec: %s", string(avctx->codec->long_name))); 00362 avcodec_close(avctx); 00363 } 00364 } 00365 } 00366 av_close_input_file(_ic); 00367 _ic = NULL; 00368 } 00369 _current = 0; 00370 _duration = 0; 00371 _video = -1; 00372 _audio = -1; 00373 _finished = true; 00374 } 00375 00376 void FFMovieContent::process(const DWORD& frame) { 00377 if (!_mediaID.empty() && _videoDecoder) { 00378 00379 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00380 int vbufs = 0; 00381 int abufs = 0; 00382 if (_playing) { 00383 if (_starting) { 00384 _frameOddEven = frame % 2; 00385 if (_audioDecoder) _audioDecoder->play(); 00386 _starting = false; 00387 } 00388 00389 bool popFrame = false; 00390 switch (config().splitType) { 00391 case 21: 00392 break; 00393 default: 00394 switch (_fps) { 00395 case 24: 00396 { 00397 // 2-3pulldown 00398 int p = (frame % 5); 00399 popFrame = p < 4 && _frameOddEven == (p % 2); 00400 } 00401 break; 00402 case 25: 00403 { 00404 int p = (frame % 12); 00405 popFrame = p == 0 || p == 2 || p == 5 || p == 7 || p == 9; 00406 } 00407 break; 00408 case 30: 00409 popFrame = _frameOddEven == (frame % 2); 00410 break; 00411 case 60: 00412 popFrame = true; 00413 break; 00414 default: 00415 popFrame = (frame % (60 / (60 - _fps))) != 0; 00416 break; 00417 } 00418 if (popFrame) { 00419 VideoFrame* vf = _videoDecoder->popFrame(); 00420 if (vf) { 00421 if (_vf) _videoDecoder->pushUsedFrame(_vf); 00422 _vf = vf; 00423 _fpsCounter.count(); 00424 } 00425 } 00426 _current++; 00427 } 00428 if (_videoDecoder) vbufs = _videoDecoder->bufferedFrames(); 00429 if (_audioDecoder) abufs = _audioDecoder->bufferedFrames(); 00430 _avgTime = _videoDecoder->getAvgTime(); 00431 00432 } else { 00433 _fpsCounter.start(); 00434 if (get("prepare") == "true") { 00435 VideoFrame* vf = _videoDecoder->viewFrame(); 00436 if (vf) _prepareVF = vf; 00437 } 00438 } 00439 unsigned long cu = _current / 60; 00440 int remain = _duration - _current; 00441 if (remain < 0) remain = 0; 00442 unsigned long re = remain / 60; 00443 string t1 = Poco::format("%02lu:%02lu:%02lu.%02d", cu / 3600, cu / 60, cu % 60, (_current / 2) % 30); 00444 string t2 = Poco::format("%02lu:%02lu:%02lu.%02d", re / 3600, re / 60, re % 60, (remain / 2) % 30); 00445 set("time", Poco::format("%s %s", t1, t2)); 00446 set("time_current", t1); 00447 set("time_remain", t2); 00448 //set("time_fps", Poco::format("%d(%0.2hf)", fps, _rate)); 00449 00450 set("status", Poco::format("%dp(%02lufps-%03.2hfms) %02d:%02d", _fps, _fpsCounter.getFPS(), _avgTime, vbufs, abufs)); 00451 } 00452 } 00453 00454 void FFMovieContent::draw(const DWORD& frame) { 00455 if (!_mediaID.empty()) { 00456 Poco::ScopedLock<Poco::FastMutex> lock(_frameLock); 00457 if (_vf && _playing) { 00458 LPDIRECT3DDEVICE9 device = _renderer.get3DDevice(); 00459 const float alpha = getF("alpha"); 00460 const int cw = config().splitSize.cx; 00461 const int ch = config().splitSize.cy; 00462 DWORD col = ((DWORD)(0xff * alpha) << 24) | 0xffffff; 00463 switch (_splitType) { 00464 case 1: 00465 { 00466 int sx = 0, sy = 0, dx = 0, dy = 0; 00467 int cww = 0; 00468 int chh = ch; 00469 while (dx < config().mainRect.right) { 00470 int ix = dx * config().splitCycles + dy / ch * cw; 00471 if (ix >= config().stageRect.right) break; 00472 if ((sx + cw) >= _vf->width()) { 00473 // はみ出る 00474 cww = _vf->width() - sx; 00475 if (ix + cww > config().stageRect.right) { 00476 cww = config().stageRect.right - ix; 00477 } 00478 _vf->draw(dx, dy, cww, chh, 0, col, sx, sy, cww, chh); 00479 sx = 0; 00480 sy += ch; 00481 if (ix + cww >= config().stageRect.right) break; 00482 if (sy >= _vf->height()) { 00483 sy = 0; 00484 chh = ch; 00485 _vf->draw(dx + cww, dy, cw - cww, chh, 0, col, sx, sy, cw - cww, chh); 00486 sx += (cw - cww); 00487 } else { 00488 if (_vf->height() - sy < ch) chh = _vf->height() - sy; 00489 // クイの分 00490 _vf->draw(dx + cww, dy, cw - cww, chh, 0, col, sx, sy, cw - cww, chh); 00491 sx += (cw - cww); 00492 } 00493 } else { 00494 cww = config().stageRect.right - ix; 00495 if (cw > cww) { 00496 _vf->draw(dx, dy, cww, chh, 0, col, sx, sy, cww, chh); 00497 break; 00498 } else { 00499 _vf->draw(dx, dy, cw, chh, 0, col, sx, sy, cw, chh); 00500 sx += cw; 00501 } 00502 } 00503 // _log.information(Poco::format("split dst: %04d,%03d src: %04d,%03d", dx, dy, sx, sy)); 00504 dy += ch; 00505 if (dy >= config().stageRect.bottom * config().splitCycles) { 00506 dx += cw; 00507 dy = 0; 00508 } 00509 } 00510 } 00511 break; 00512 00513 case 2: 00514 { 00515 // device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); 00516 // RECT scissorRect; 00517 // device->GetScissorRect(&scissorRect); 00518 // device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); 00519 // device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); 00520 // device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00521 // device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00522 int sw = L(_w / cw); 00523 if (sw <= 0) sw = 1; 00524 int sh = L(_h / ch); 00525 if (sh <= 0) sh = 1; 00526 for (int sy = 0; sy < sh; sy++) { 00527 int ox = (sy % 2) * cw * 8 + config().stageRect.left; 00528 int oy = (sy / 2) * ch * config().splitCycles + config().stageRect.top; 00529 // int ox = (sy % 2) * cw * 8; 00530 // int oy = (sy / 2) * ch * 4; 00531 for (int sx = 0; sx < sw; sx++) { 00532 int dx = (sx / config().splitCycles) * cw; 00533 int dy = ch * (config().splitCycles - 1) - (sx % config().splitCycles) * ch; 00534 _vf->draw(ox + dx, oy + dy, cw, ch, 0, col, sx * cw, sy * ch, cw, ch); 00535 // _renderer.drawTexture(ox + dx, oy + dy, cw, ch, sx * cw, sy * ch, cw, ch, _target, col, col, col, col); 00536 } 00537 } 00538 // device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00539 // device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00540 // device->SetScissorRect(&scissorRect); 00541 } 00542 break; 00543 00544 case 11: 00545 { 00546 if (_vf->height() == 120) { 00547 _vf->draw(0, 360, 320, 120, 0, col, 2880, 0, 320, 120); 00548 _vf->draw(0, 240, 960, 120, 0, col, 1920, 0, 960, 120); 00549 _vf->draw(0, 120, 960, 120, 0, col, 960, 0, 960, 120); 00550 _vf->draw(0, 0, 960, 120, 0, col, 0, 0, 960, 120); 00551 } else { 00552 int w = config().mainRect.right; 00553 int h = config().mainRect.bottom; 00554 if (_vf->width() > w || _vf->height() > h) { 00555 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00556 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00557 _vf->draw( 0, 0, w, h, 1, col); 00558 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00559 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00560 } else { 00561 // _vf->draw(0, 0); 00562 _vf->draw(0, 0, -1, -1, 0, col); 00563 } 00564 } 00565 } 00566 break; 00567 00568 default: 00569 { 00570 RECT rect = config().stageRect; 00571 string aspectMode = get("aspect-mode"); 00572 if (aspectMode == "fit") { 00573 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00574 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00575 _vf->draw(L(_x), L(_y), L(_w), L(_h), 0, col); 00576 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00577 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00578 00579 } else { 00580 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00581 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00582 if (alpha > 0.0f) { 00583 DWORD base = ((DWORD)(0xff * alpha) << 24) | 0x000000; 00584 _renderer.drawTexture(_x, _y, _w, _h, NULL, 0, base, base, base, base); 00585 float dar = _videoDecoder->getDisplayAspectRatio(); 00586 if (_h * dar > _w) { 00587 // 画角よりディスプレイサイズは横長 00588 long h = _w / dar; 00589 long dy = (_h - h) / 2; 00590 _vf->draw(L(_x), L(_y + dy), L(_w), h, 0, col); 00591 } else { 00592 long w = _h * dar; 00593 long dx = (_w - w) / 2; 00594 _vf->draw(L(_x + dx), L(_y), w, L(_h), 0, col); 00595 } 00596 } 00597 00598 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00599 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00600 } 00601 } 00602 break; 00603 } 00604 00605 } else if (_playing && config().splitType == 21) { 00606 LPDIRECT3DDEVICE9 device = _renderer.get3DDevice(); 00607 float alpha = getF("alpha"); 00608 int cw = config().splitSize.cx; 00609 int ch = config().splitSize.cy; 00610 DWORD col = ((DWORD)(0xff * alpha) << 24) | 0xffffff; 00611 00612 int remain = _duration - _current; 00613 if (_videoDecoder->bufferedFrames() >= ((remain > 8)?8:remain)) { 00614 for (int y = 0; y < 2; y++) { 00615 for (int x = 0; x < 4 && _current <= _duration; x++) { 00616 VideoFrame* vf = _videoDecoder->popFrame(); 00617 if (vf) { 00618 int w = vf->width(); 00619 int h = vf->height(); 00620 vf->draw(L(x * w), L(y * h), L(w), L(h), 0, 0xffffffff); 00621 _videoDecoder->pushUsedFrame(vf); 00622 _fpsCounter.count(); 00623 _current++; 00624 } 00625 } 00626 } 00627 _fpsCounter.count(); 00628 } 00629 00630 } else if (get("prepare") == "true" && _prepareVF) { 00631 int sy = L(getF("itemNo") * 20); 00632 _prepareVF->draw(700, 600 + sy, 324, 20, 1, 0x99ffffff); 00633 } 00634 } 00635 } 00636 00640 const Uint32 FFMovieContent::getFPS() { 00641 return _fpsCounter.getFPS(); 00642 } 00643 00647 const float FFMovieContent::getAvgTime() const { 00648 return _avgTime; 00649 } 00650 00654 const DWORD FFMovieContent::currentTime() { 00655 return _playTimer.getTime(); 00656 } 00657 00661 const DWORD FFMovieContent::timeLeft() { 00662 long left = (_duration * 1000 / 30) - currentTime(); 00663 if (left < 0) left = 0; 00664 return left; 00665 } 00666 00667 #endif