|
MythTV
0.26-pre
|
00001 // POSIX headers 00002 #include <stdlib.h> 00003 00004 #ifndef USING_MINGW // dlfcn for mingw defined in compat.h 00005 #include <dlfcn.h> // needed for dlopen(), dlerror(), dlsym(), and dlclose() 00006 #else 00007 #include "compat.h" 00008 #endif 00009 00010 // Qt headers 00011 #include <QDir> 00012 #include <QStringList> 00013 00014 // MythTV headers 00015 #include "mythcontext.h" 00016 #include "filtermanager.h" 00017 #include "mythdirs.h" 00018 00019 #define LOC QString("FilterManager: ") 00020 00021 static const char *FmtToString(VideoFrameType ft) 00022 { 00023 switch(ft) 00024 { 00025 case FMT_NONE: 00026 return "NONE"; 00027 case FMT_RGB24: 00028 return "RGB24"; 00029 case FMT_YV12: 00030 return "YV12"; 00031 case FMT_ARGB32: 00032 return "ARGB32"; 00033 case FMT_YUV422P: 00034 return "YUV422P"; 00035 default: 00036 return "INVALID"; 00037 } 00038 } 00039 00040 FilterChain::~FilterChain() 00041 { 00042 vector<VideoFilter*>::iterator it = filters.begin(); 00043 for (; it != filters.end(); ++it) 00044 { 00045 VideoFilter *filter = *it; 00046 if (filter->opts) 00047 free(filter->opts); 00048 if (filter->cleanup) 00049 filter->cleanup(filter); 00050 dlclose(filter->handle); 00051 free(filter); 00052 } 00053 filters.clear(); 00054 } 00055 00056 void FilterChain::ProcessFrame(VideoFrame *frame, FrameScanType scan) 00057 { 00058 if (!frame) 00059 return; 00060 00061 vector<VideoFilter*>::iterator it = filters.begin(); 00062 for (; it != filters.end(); ++it) 00063 (*it)->filter(*it, frame, kScan_Intr2ndField == scan); 00064 } 00065 00066 FilterManager::FilterManager() 00067 { 00068 QDir FiltDir(GetFiltersDir()); 00069 00070 FiltDir.setFilter(QDir::Files | QDir::Readable); 00071 if (FiltDir.exists()) 00072 { 00073 QStringList LibList = FiltDir.entryList(); 00074 for (QStringList::iterator i = LibList.begin(); i != LibList.end(); 00075 ++i) 00076 { 00077 QString path = FiltDir.filePath(*i); 00078 if (path.length() <= 1) 00079 continue; 00080 00081 LOG(VB_PLAYBACK | VB_FILE, LOG_INFO, LOC + 00082 QString("Loading filter '%1'").arg(path)); 00083 00084 if (!LoadFilterLib(path)) 00085 { 00086 LOG(VB_GENERAL, LOG_WARNING, LOC + 00087 QString("Failed to load filter library: %1").arg(path)); 00088 } 00089 } 00090 } 00091 else 00092 LOG(VB_GENERAL, LOG_ERR, 00093 "Filter dir '" + FiltDir.absolutePath() + "' doesn't exist?"); 00094 } 00095 00096 FilterManager::~FilterManager() 00097 { 00098 filter_map_t::iterator itf = filters.begin(); 00099 for (; itf != filters.end(); ++itf) 00100 { 00101 FilterInfo *tmp = itf->second; 00102 itf->second = NULL; 00103 00104 free(tmp->name); 00105 free(tmp->descript); 00106 free(tmp->libname); 00107 delete [] (tmp->formats); 00108 delete tmp; 00109 } 00110 filters.clear(); 00111 00112 library_map_t::iterator ith = dlhandles.begin(); 00113 for (; ith != dlhandles.end(); ++ith) 00114 { 00115 void *tmp = ith->second; 00116 ith->second = NULL; 00117 dlclose(tmp); 00118 } 00119 dlhandles.clear(); 00120 } 00121 00122 bool FilterManager::LoadFilterLib(const QString &path) 00123 { 00124 dlerror(); // clear out any pre-existing dlerrors 00125 00126 void *dlhandle = NULL; 00127 library_map_t::iterator it = dlhandles.find(path); 00128 if (it != dlhandles.end()) 00129 dlhandle = it->second; 00130 00131 if (!dlhandle) 00132 { 00133 QByteArray apath = path.toAscii(); 00134 dlhandle = dlopen(apath.constData(), RTLD_LAZY); 00135 if (!dlhandle) 00136 { 00137 const char *errmsg = dlerror(); 00138 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to load filter library: " + 00139 QString("'%1'").arg(path) + "\n\t\t\t" + errmsg); 00140 return false; 00141 } 00142 dlhandles[path] = dlhandle; 00143 } 00144 00145 const ConstFilterInfo *filtInfo = (const ConstFilterInfo*) 00146 dlsym(dlhandle, "filter_table"); 00147 00148 if (!filtInfo) 00149 { 00150 const char *errmsg = dlerror(); 00151 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to load filter symbol: " + 00152 QString("'%1'").arg(path) + "\n\t\t\t" + errmsg); 00153 return false; 00154 } 00155 00156 for (; filtInfo->filter_init; filtInfo++) 00157 { 00158 if (!filtInfo->filter_init || !filtInfo->name || !filtInfo->formats) 00159 break; 00160 00161 FilterInfo *newFilter = new FilterInfo; 00162 newFilter->filter_init = NULL; 00163 newFilter->name = strdup(filtInfo->name); 00164 newFilter->descript = strdup(filtInfo->descript); 00165 00166 int i = 0; 00167 for (; filtInfo->formats[i].in != FMT_NONE; i++); 00168 00169 newFilter->formats = new FmtConv[i + 1]; 00170 memcpy(newFilter->formats, filtInfo->formats, 00171 sizeof(FmtConv) * (i + 1)); 00172 00173 QByteArray libname = path.toAscii(); 00174 newFilter->libname = strdup(libname.constData()); 00175 filters[newFilter->name] = newFilter; 00176 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("filters[%1] = 0x%2") 00177 .arg(newFilter->name).arg((uint64_t)newFilter,0,16)); 00178 } 00179 return true; 00180 } 00181 00182 const FilterInfo *FilterManager::GetFilterInfo(const QString &name) const 00183 { 00184 const FilterInfo *finfo = NULL; 00185 filter_map_t::const_iterator it = filters.find(name); 00186 if (it != filters.end()) 00187 finfo = it->second; 00188 00189 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("GetFilterInfo(%1)").arg(name) + 00190 QString(" returning: 0x%1").arg((uint64_t)finfo,0,16)); 00191 00192 return finfo; 00193 } 00194 00195 FilterChain *FilterManager::LoadFilters(QString Filters, 00196 VideoFrameType &inpixfmt, 00197 VideoFrameType &outpixfmt, int &width, 00198 int &height, int &bufsize, 00199 int max_threads) 00200 { 00201 if (Filters.toLower() == "none") 00202 return NULL; 00203 00204 vector<const FilterInfo*> FiltInfoChain; 00205 FilterChain *FiltChain = new FilterChain; 00206 vector<FmtConv*> FmtList; 00207 const FilterInfo *FI; 00208 const FilterInfo *FI2; 00209 QString Opts; 00210 const FilterInfo *Convert = GetFilterInfo("convert"); 00211 QStringList OptsList; 00212 QStringList FilterList = Filters.split(",", QString::SkipEmptyParts); 00213 VideoFilter *NewFilt = NULL; 00214 FmtConv *FC, *FC2, *S1, *S2, *S3; 00215 VideoFrameType ifmt; 00216 unsigned int i; 00217 int nbufsize; 00218 int cbufsize; 00219 int postfilt_width = width; 00220 int postfilt_height = height; 00221 00222 for (QStringList::Iterator i = FilterList.begin(); 00223 i != FilterList.end(); ++i) 00224 { 00225 QString FiltName = (*i).section('=', 0, 0); 00226 QString FiltOpts = (*i).section('=', 1); 00227 00228 if (FiltName.contains("opengl", Qt::CaseInsensitive) || 00229 FiltName.contains("vdpau", Qt::CaseInsensitive)) 00230 continue; 00231 00232 FI = GetFilterInfo(FiltName); 00233 00234 if (FI) 00235 { 00236 FiltInfoChain.push_back(FI); 00237 OptsList.push_back(FiltOpts); 00238 } 00239 else 00240 { 00241 LOG(VB_GENERAL, LOG_ERR, LOC + 00242 QString("Failed to load filter '%1', " 00243 "no such filter exists").arg(FiltName)); 00244 FiltInfoChain.clear(); 00245 break; 00246 } 00247 } 00248 00249 ifmt = inpixfmt; 00250 for (i = 0; i < FiltInfoChain.size(); i++) 00251 { 00252 S1 = S2 = S3 = NULL; 00253 FI = FiltInfoChain[i]; 00254 if (FiltInfoChain.size() - i == 1) 00255 { 00256 for (FC = FI->formats; FC->in != FMT_NONE; FC++) 00257 { 00258 if (FC->out == outpixfmt && FC->in == ifmt) 00259 { 00260 S1 = FC; 00261 break; 00262 } 00263 if (FC->in == ifmt && !S2) 00264 S2 = FC; 00265 if (FC->out == outpixfmt && !S3) 00266 S3 = FC; 00267 } 00268 } 00269 else 00270 { 00271 FI2 = FiltInfoChain[i+1]; 00272 for (FC = FI->formats; FC->in != FMT_NONE; FC++) 00273 { 00274 for (FC2 = FI2->formats; FC2->in != FMT_NONE; FC2++) 00275 { 00276 if (FC->in == ifmt && FC->out == FC2->in) 00277 { 00278 S1 = FC; 00279 break; 00280 } 00281 if (FC->out == FC2->in && !S3) 00282 S3 = FC; 00283 } 00284 if (S1) 00285 break; 00286 if (FC->in == ifmt && !S2) 00287 S2 = FC; 00288 } 00289 } 00290 00291 if (S1) 00292 FC = S1; 00293 else if (S2) 00294 FC = S2; 00295 else if (S3) 00296 FC = S3; 00297 else 00298 FC = FI->formats; 00299 00300 if (FC->in != ifmt && (i > 0 || ifmt != FMT_NONE)) 00301 { 00302 if (!Convert) 00303 { 00304 LOG(VB_GENERAL, LOG_ERR, "FilterManager: format conversion " 00305 "needed but convert filter not found"); 00306 FiltInfoChain.clear(); 00307 break; 00308 } 00309 FiltInfoChain.insert(FiltInfoChain.begin() + i, Convert); 00310 OptsList.insert(i, QString ()); 00311 FmtList.push_back(new FmtConv); 00312 if (FmtList.back()) 00313 { 00314 FmtList.back()->in = ifmt; 00315 FmtList.back()->out = FC->in; 00316 i++; 00317 } 00318 else 00319 { 00320 LOG(VB_GENERAL, LOG_ERR, 00321 "FilterManager: memory allocation " 00322 "failure, returning empty filter chain"); 00323 FiltInfoChain.clear(); 00324 break; 00325 } 00326 } 00327 FmtList.push_back(new FmtConv); 00328 if (FmtList.back()) 00329 { 00330 FmtList.back()->in = FC->in; 00331 FmtList.back()->out = FC->out; 00332 } 00333 else 00334 { 00335 LOG(VB_GENERAL, LOG_ERR, 00336 "FilterManager: memory allocation failure, " 00337 "returning empty filter chain"); 00338 FiltInfoChain.clear(); 00339 break; 00340 } 00341 ifmt = FC->out; 00342 } 00343 00344 if (ifmt != outpixfmt && outpixfmt != FMT_NONE && 00345 (FiltInfoChain.size() || inpixfmt != FMT_NONE)) 00346 { 00347 if (!Convert) 00348 { 00349 LOG(VB_GENERAL, LOG_ERR, "FilterManager: format conversion " 00350 "needed but convert filter not found"); 00351 FiltInfoChain.clear(); 00352 } 00353 else 00354 { 00355 FiltInfoChain.push_back(Convert); 00356 OptsList.push_back( QString ()); 00357 FmtList.push_back(new FmtConv); 00358 if (FmtList.back()) 00359 { 00360 FmtList.back()->in = ifmt; 00361 FmtList.back()->out = outpixfmt; 00362 } 00363 else 00364 { 00365 LOG(VB_GENERAL, LOG_ERR, 00366 "FilterManager: memory allocation " 00367 "failure, returning empty filter chain"); 00368 FiltInfoChain.clear(); 00369 } 00370 } 00371 } 00372 00373 nbufsize = -1; 00374 00375 if (FiltInfoChain.empty()) 00376 { 00377 delete FiltChain; 00378 FiltChain = NULL; 00379 } 00380 00381 for (i = 0; i < FiltInfoChain.size(); i++) 00382 { 00383 QByteArray tmp = OptsList[i].toLocal8Bit(); 00384 NewFilt = LoadFilter(FiltInfoChain[i], FmtList[i]->in, 00385 FmtList[i]->out, postfilt_width, 00386 postfilt_height, tmp.constData(), 00387 max_threads); 00388 00389 if (!NewFilt) 00390 { 00391 delete FiltChain; 00392 LOG(VB_GENERAL, LOG_ERR, QString("FilterManager: failed to load " 00393 "filter %1 %2->%3 with args %4") 00394 .arg(FiltInfoChain[i]->name) 00395 .arg(FmtToString(FmtList[i]->in)) 00396 .arg(FmtToString(FmtList[i]->out)) 00397 .arg(OptsList[i])); 00398 FiltChain = NULL; 00399 nbufsize = -1; 00400 break; 00401 } 00402 00403 if (NewFilt->filter && FiltChain) 00404 { 00405 FiltChain->Append(NewFilt); 00406 } 00407 else 00408 { 00409 if (NewFilt->opts) 00410 free(NewFilt->opts); 00411 if (NewFilt->cleanup) 00412 NewFilt->cleanup(NewFilt); 00413 dlclose(NewFilt->handle); 00414 free(NewFilt); 00415 } 00416 00417 switch (FmtList[i]->out) 00418 { 00419 case FMT_YV12: 00420 cbufsize = postfilt_width * postfilt_height * 3 / 2; 00421 break; 00422 case FMT_YUV422P: 00423 cbufsize = postfilt_width * postfilt_height * 2; 00424 break; 00425 case FMT_RGB24: 00426 cbufsize = postfilt_width * postfilt_height * 3; 00427 break; 00428 case FMT_ARGB32: 00429 cbufsize = postfilt_width * postfilt_height * 4; 00430 break; 00431 default: 00432 cbufsize = 0; 00433 } 00434 00435 if (cbufsize > nbufsize) 00436 nbufsize = cbufsize; 00437 } 00438 00439 if (FiltChain) 00440 { 00441 if (inpixfmt == FMT_NONE) 00442 inpixfmt = FmtList.front()->in; 00443 if (outpixfmt == FMT_NONE) 00444 inpixfmt = FmtList.back()->out; 00445 width = postfilt_width; 00446 height = postfilt_height; 00447 } 00448 else 00449 { 00450 if (inpixfmt == FMT_NONE && outpixfmt == FMT_NONE) 00451 inpixfmt = outpixfmt = FMT_YV12; 00452 else if (inpixfmt == FMT_NONE) 00453 inpixfmt = outpixfmt; 00454 else if (outpixfmt == FMT_NONE) 00455 outpixfmt = inpixfmt; 00456 } 00457 00458 switch (inpixfmt) 00459 { 00460 case FMT_YV12: 00461 cbufsize = postfilt_width * postfilt_height * 3 / 2; 00462 break; 00463 case FMT_YUV422P: 00464 cbufsize = postfilt_width * postfilt_height * 2; 00465 break; 00466 case FMT_RGB24: 00467 cbufsize = postfilt_width * postfilt_height * 3; 00468 break; 00469 case FMT_ARGB32: 00470 cbufsize = postfilt_width * postfilt_height * 4; 00471 break; 00472 default: 00473 cbufsize = 0; 00474 } 00475 00476 if (cbufsize > nbufsize) 00477 nbufsize = cbufsize; 00478 00479 bufsize = nbufsize; 00480 00481 vector<FmtConv*>::iterator it = FmtList.begin(); 00482 for (; it != FmtList.end(); ++it) 00483 delete *it; 00484 FmtList.clear(); 00485 00486 return FiltChain; 00487 } 00488 00489 VideoFilter * FilterManager::LoadFilter(const FilterInfo *FiltInfo, 00490 VideoFrameType inpixfmt, 00491 VideoFrameType outpixfmt, int &width, 00492 int &height, const char *opts, 00493 int max_threads) 00494 { 00495 void *handle; 00496 VideoFilter *Filter; 00497 00498 if (FiltInfo == NULL) 00499 { 00500 LOG(VB_GENERAL, LOG_ERR, "FilterManager: LoadFilter called with NULL" 00501 "FilterInfo"); 00502 return NULL; 00503 } 00504 00505 if (FiltInfo->libname == NULL) 00506 { 00507 LOG(VB_GENERAL, LOG_ERR, 00508 "FilterManager: LoadFilter called with invalid " 00509 "FilterInfo (libname is NULL)"); 00510 return NULL; 00511 } 00512 00513 handle = dlopen(FiltInfo->libname, RTLD_NOW); 00514 00515 if (!handle) 00516 { 00517 LOG(VB_GENERAL, LOG_ERR, 00518 QString("FilterManager: unable to load " 00519 "shared library '%1', dlopen reports error '%2'") 00520 .arg(FiltInfo->libname) 00521 .arg(dlerror())); 00522 return NULL; 00523 } 00524 00525 const ConstFilterInfo *filtInfo 00526 = (const ConstFilterInfo*)dlsym(handle, "filter_table"); 00527 00528 if (!filtInfo || !filtInfo->filter_init) 00529 { 00530 LOG(VB_GENERAL, LOG_ERR, 00531 QString("FilterManager: unable to load filter " 00532 "'%1' from shared library '%2', dlopen reports error '%3'") 00533 .arg(FiltInfo->name) 00534 .arg(FiltInfo->libname) 00535 .arg(dlerror())); 00536 dlclose(handle); 00537 return NULL; 00538 } 00539 00540 Filter = filtInfo->filter_init(inpixfmt, outpixfmt, &width, &height, 00541 const_cast<char*>(opts), max_threads); 00542 00543 if (Filter == NULL) 00544 { 00545 dlclose(handle); 00546 return NULL; 00547 } 00548 00549 Filter->handle = handle; 00550 Filter->inpixfmt = inpixfmt; 00551 Filter->outpixfmt = outpixfmt; 00552 if (opts) 00553 Filter->opts = strdup(opts); 00554 else 00555 Filter->opts = NULL; 00556 Filter->info = const_cast<FilterInfo*>(FiltInfo); 00557 return Filter; 00558 }
1.7.6.1