Ticket #3361: 3361-v2.patch
File 3361-v2.patch, 52.2 KB (added by , 16 years ago) |
---|
-
libs/libmythtv/previewgenerator.cpp
63 63 PreviewGenerator::PreviewGenerator(const ProgramInfo *pginfo, 64 64 bool local_only) 65 65 : programInfo(*pginfo), localOnly(local_only), isConnected(false), 66 createSockets(false), serverSock(NULL), pathname(pginfo->pathname) 66 createSockets(false), serverSock(NULL), pathname(pginfo->pathname), 67 timeInSeconds(true), captureTime(-1), outFileName(QString::null), 68 outSize(0,0) 67 69 { 68 70 if (IsLocal()) 69 71 return; … … 81 83 "'%1' is not local, " 82 84 "\n\t\t\treplacing with '%2', which is local.") 83 85 .arg(pathname).arg(localFN); 84 VERBOSE(VB_ RECORD, LOC + msg);86 VERBOSE(VB_IMPORTANT, LOC + msg); 85 87 pathname = localFN; 86 88 } 87 89 … … 90 92 TeardownAll(); 91 93 } 92 94 95 void PreviewGenerator::SetOutputFilename(const QString &fileName) 96 { 97 outFileName = QDeepCopy<QString>(fileName); 98 } 99 93 100 void PreviewGenerator::TeardownAll(void) 94 101 { 95 102 if (!isConnected) … … 109 116 previewLock.unlock(); 110 117 usleep(5000); 111 118 } 112 VERBOSE(VB_ PLAYBACK, LOC + "previewThreadDone took "<<t.elapsed()<<"ms");119 VERBOSE(VB_IMPORTANT, LOC + "previewThreadDone took "<<t.elapsed()<<"ms"); 113 120 disconnectSafe(); 114 121 } 115 122 … … 150 157 pthread_detach(previewThread); 151 158 } 152 159 153 /** \fn PreviewGenerator::Run (void)160 /** \fn PreviewGenerator::RunReal(void) 154 161 * \brief This call creates a preview without starting a new thread. 155 162 */ 156 void PreviewGenerator::Run(void)163 bool PreviewGenerator::RunReal(void) 157 164 { 158 if (IsLocal()) 165 bool ok = false; 166 bool is_local = IsLocal(); 167 if (is_local && LocalPreviewRun()) 159 168 { 160 LocalPreviewRun();169 ok = true; 161 170 } 162 171 else if (!localOnly) 163 172 { 164 RemotePreviewRun(); 173 if (is_local) 174 { 175 VERBOSE(VB_IMPORTANT, LOC_WARN + "Failed to save preview." 176 "\n\t\t\tYou may need to check user and group ownership on" 177 "\n\t\t\tyour frontend and backend for quicker previews.\n" 178 "\n\t\t\tAttempting to regenerate preview on backend.\n"); 179 } 180 ok = RemotePreviewRun(); 165 181 } 166 182 else 167 183 { 168 184 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Run() file not local: '%1'") 169 185 .arg(pathname)); 170 186 } 187 188 return ok; 171 189 } 172 190 191 bool PreviewGenerator::Run(void) 192 { 193 bool ok = false; 194 if (!IsLocal()) 195 { 196 if (!localOnly) 197 { 198 ok = RemotePreviewRun(); 199 } 200 else 201 { 202 VERBOSE(VB_IMPORTANT, LOC_ERR + 203 QString("Run() file not local: '%1'") 204 .arg(pathname)); 205 } 206 } 207 else 208 { 209 // This is where we fork and run mythbackend to actually make preview 210 QString command = "mythbackend --generate-preview "; 211 command += QString("%1x%2") 212 .arg(outSize.width()).arg(outSize.height()); 213 if (captureTime >= 0) 214 command += QString("@%1%2") 215 .arg(captureTime).arg(timeInSeconds ? "s" : "f"); 216 command += " "; 217 command += QString("--chanid %1 ").arg(programInfo.chanid); 218 command += QString("--starttime %1 ") 219 .arg(programInfo.recstartts.toString("yyyyMMddhhmmss")); 220 if (!outFileName.isEmpty()) 221 command += QString("--outfile %1 ").arg(outFileName); 222 223 int ret = myth_system(command); 224 if (ret) 225 { 226 VERBOSE(VB_IMPORTANT, LOC_ERR + "Encountered problems running " + 227 QString("'%1'").arg(command)); 228 } 229 else 230 { 231 VERBOSE(VB_IMPORTANT, LOC + "Preview process returned 0."); 232 QString outname = (!outFileName.isEmpty()) ? 233 outFileName : (pathname + ".png"); 234 235 QFileInfo fi(outname); 236 ok = (fi.exists() && fi.isReadable() && fi.size()); 237 if (ok) 238 VERBOSE(VB_IMPORTANT, LOC + "Preview process ran ok."); 239 else 240 { 241 VERBOSE(VB_IMPORTANT, LOC_ERR + "Preview process not ok." + 242 QString("\n\t\t\tfileinfo(%1)").arg(outname) 243 <<" exits: "<<fi.exists() 244 <<" readable: "<<fi.isReadable() 245 <<" size: "<<fi.size()); 246 } 247 } 248 } 249 250 if (ok) 251 { 252 QMutexLocker locker(&previewLock); 253 emit previewReady(&programInfo); 254 } 255 256 return ok; 257 } 258 173 259 void *PreviewGenerator::PreviewRun(void *param) 174 260 { 175 261 // Lower scheduling priority, to avoid problems with recordings. … … 191 277 return serverSock; 192 278 } 193 279 194 voidPreviewGenerator::RemotePreviewRun(void)280 bool PreviewGenerator::RemotePreviewRun(void) 195 281 { 196 282 QStringList strlist = "QUERY_GENPIXMAP"; 197 283 programInfo.ToStringList(strlist); … … 202 288 if (!RemotePreviewSetup()) 203 289 { 204 290 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to open sockets."); 205 return ;291 return false; 206 292 } 207 293 208 294 if (serverSock) … … 218 304 ok = gContext->SendReceiveStringList(strlist); 219 305 } 220 306 221 if (ok && (strlist[0] == "OK")) 222 { 223 QMutexLocker locker(&previewLock); 224 emit previewReady(&programInfo); 225 } 307 return (ok && strlist.size() && (strlist[0] == "OK")); 226 308 } 227 309 228 310 void PreviewGenerator::RemotePreviewTeardown(void) … … 236 318 237 319 bool PreviewGenerator::SavePreview(QString filename, 238 320 const unsigned char *data, 239 uint width, uint height, float aspect) 321 uint width, uint height, float aspect, 322 int desired_width, int desired_height) 240 323 { 241 324 if (!data || !width || !height) 242 325 return false; … … 245 328 width, height, 32, NULL, 65536 * 65536, 246 329 QImage::LittleEndian); 247 330 248 float ppw = gContext->GetNumSetting("PreviewPixmapWidth", 160); 249 float pph = gContext->GetNumSetting("PreviewPixmapHeight", 120); 331 float ppw = max(desired_width, 0); 332 float pph = max(desired_height, 0); 333 bool desired_size_exactly_specified = true; 334 if ((ppw < 1.0f) && (pph < 1.0f)) 335 { 336 ppw = gContext->GetNumSetting("PreviewPixmapWidth", 160); 337 pph = gContext->GetNumSetting("PreviewPixmapHeight", 120); 338 desired_size_exactly_specified = false; 339 } 250 340 251 aspect = (aspect <= 0) ? ((float) width) / height : aspect; 341 aspect = (aspect <= 0.0f) ? ((float) width) / height : aspect; 342 pph = (pph < 1.0f) ? (ppw / aspect) : pph; 343 ppw = (ppw < 1.0f) ? (pph * aspect) : ppw; 252 344 253 if (aspect > ppw / pph) 254 pph = rint(ppw / aspect); 255 else 256 ppw = rint(pph * aspect); 345 if (!desired_size_exactly_specified) 346 { 347 if (aspect > ppw / pph) 348 pph = (ppw / aspect); 349 else 350 ppw = (pph * aspect); 351 } 257 352 353 ppw = max(1.0f, ppw); 354 pph = max(1.0f, pph);; 355 258 356 QImage small_img = img.smoothScale((int) ppw, (int) pph); 259 357 260 358 if (small_img.save(filename.ascii(), "PNG")) 261 359 { 262 360 chmod(filename.ascii(), 0666); // Let anybody update it 361 362 VERBOSE(VB_GENERAL, LOC + 363 QString("Saved preview '%0' %1x%2") 364 .arg(filename).arg((int) ppw).arg((int) pph)); 365 263 366 return true; 264 367 } 265 368 … … 270 373 { 271 374 chmod(newfile.ascii(), 0666); 272 375 rename(newfile.ascii(), filename.ascii()); 376 377 VERBOSE(VB_GENERAL, LOC + 378 QString("Saved preview '%0' %1x%2") 379 .arg(filename).arg((int) ppw).arg((int) pph)); 380 273 381 return true; 274 382 } 275 383 … … 277 385 return false; 278 386 } 279 387 280 voidPreviewGenerator::LocalPreviewRun(void)388 bool PreviewGenerator::LocalPreviewRun(void) 281 389 { 390 #if 0 391 char *memaddr = (char*)0x1111; 392 memset(memaddr, 0, 0xFFFFFFFF); // try to cause segfault 393 #endif 394 282 395 programInfo.MarkAsInUse(true, kInUseID); 283 396 284 397 float aspect = 0; 285 int secsin = (gContext->GetNumSetting("PreviewPixmapOffset", 64) +286 gContext->GetNumSetting("RecordPreRoll", 0));287 398 int len, width, height, sz; 399 long long captime = captureTime; 400 if (captime < 0) 401 { 402 timeInSeconds = true; 403 captime = (gContext->GetNumSetting("PreviewPixmapOffset", 64) + 404 gContext->GetNumSetting("RecordPreRoll", 0)); 405 } 288 406 289 407 len = width = height = sz = 0; 290 408 unsigned char *data = (unsigned char*) 291 GetScreenGrab(&programInfo, pathname, secsin, 409 GetScreenGrab(&programInfo, pathname, 410 captime, timeInSeconds, 292 411 sz, width, height, aspect); 293 294 bool ok = SavePreview(pathname + ".png",295 data, width, height, aspect);296 if (ok)297 {298 QMutexLocker locker(&previewLock);299 emit previewReady(&programInfo);300 }301 412 413 QString outname = pathname + ".png"; 414 outname = (outFileName.isEmpty()) ? outname : outFileName; 415 416 int dw = (outSize.width() < 0) ? width : outSize.width(); 417 int dh = (outSize.height() < 0) ? height : outSize.height(); 418 419 bool ok = SavePreview(outname, data, width, height, aspect, dw, dh); 420 302 421 if (data) 303 422 delete[] data; 304 423 305 424 programInfo.MarkAsInUse(false); 306 425 307 // local update failed, try remote... 308 if (!ok && !localOnly) 309 { 310 VERBOSE(VB_IMPORTANT, LOC_WARN + "Failed to save preview." 311 "\n\t\t\tYou may need to check user and group ownership" 312 "\n\t\t\ton your frontend and backend for quicker previews." 313 "\n\n\t\t\tAttempting to regenerate preview on backend.\n"); 314 315 RemotePreviewRun(); 316 } 426 return ok; 317 427 } 318 428 319 429 bool PreviewGenerator::IsLocal(void) const … … 322 432 return (QFileInfo(pathname).exists() && QFileInfo(pathdir).isWritable()); 323 433 } 324 434 325 /** 326 * \brief Saves a screenshot to a file. 327 * 328 * \param pginfo Recording to grab from. 329 * \param outFile Filename to save the image to 330 * \param frameNumber Frame Number to capture 331 * \param thumbWidth Width of desired image 332 * \param thumbHeight Height of desired image 333 * \return True if successful, false otherwise. 334 */ 335 bool PreviewGenerator::SaveScreenshot(ProgramInfo *pginfo, QString &outFile, 336 long long frameNumber, int &thumbWidth, int &thumbHeight) 337 { 338 float desWidth = (float)thumbWidth; 339 float desHeight = (float)thumbHeight; 340 float frameAspect = 0.0; 341 char *retbuf = NULL; 342 int bufferLen = 0; 343 int frameWidth = 0; 344 int frameHeight = 0; 345 346 if (!pginfo) 347 return false; 348 349 QString inFile = pginfo->GetPlaybackURL(); 350 RingBuffer *rbuf = new RingBuffer(inFile, false, false, 0); 351 352 if (!rbuf->IsOpen()) 353 { 354 VERBOSE(VB_IMPORTANT, LOC_ERR + 355 "SaveScreenshot: Could not open file: " + 356 QString("'%1'").arg(inFile)); 357 delete rbuf; 358 return false; 359 } 360 361 NuppelVideoPlayer *nvp = new NuppelVideoPlayer(kInUseID, pginfo); 362 nvp->SetRingBuffer(rbuf); 363 364 retbuf = nvp->GetScreenGrabAtFrame(frameNumber, true, bufferLen, 365 frameWidth, frameHeight, frameAspect); 366 367 if (thumbWidth == -1) 368 desWidth = frameWidth; 369 if (thumbHeight == -1) 370 desHeight = frameHeight; 371 372 delete nvp; 373 delete rbuf; 374 375 if (!retbuf || bufferLen == 0) 376 return false; 377 378 if (frameAspect <= 0) 379 frameAspect = frameWidth / frameHeight; 380 381 const QImage img((unsigned char*) retbuf, 382 frameWidth, frameHeight, 32, NULL, 65536 * 65536, 383 QImage::LittleEndian); 384 385 if (frameAspect > desWidth / desHeight) 386 desHeight = rint(desWidth / frameAspect); 387 else 388 desWidth = rint(desHeight * frameAspect); 389 390 QImage small_img = img.smoothScale((int) desWidth, (int) desHeight); 391 QString type = "PNG"; 392 393 if (outFile.right(4).lower() == ".png") 394 type = outFile.right(3).upper(); 395 else 396 VERBOSE(VB_IMPORTANT, LOC_WARN + QString("SaveScreenshot: The filename " 397 "(%1) does not end in .png, but we only support png format. " 398 "The file will contain a PNG formatted image.") 399 .arg(outFile)); 400 401 if (small_img.save(outFile.ascii(), type)) 402 chmod(outFile.ascii(), 0666); 403 else 404 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("SaveScreenshot: unable to " 405 "open save image").arg(outFile)); 406 407 delete retbuf; 408 409 thumbWidth = (int)desWidth; 410 thumbHeight = (int)desHeight; 411 412 return true; 413 } 414 415 /** \fn PreviewGenerator::GetScreenGrab(const ProgramInfo*,const QString&,int,int&,int&,int&,float&) 435 /** \fn PreviewGenerator::GetScreenGrab(const ProgramInfo*, const QString&, 436 long long, bool, int&, int&, int&, float&) 416 437 * \brief Returns a PIX_FMT_RGBA32 buffer containg a frame from the video. 417 438 * 418 439 * \param pginfo Recording to grab from. 419 440 * \param filename File containing recording. 420 * \param se condsin Seconds into the video to seek before441 * \param seektime Seconds or frames into the video to seek before 421 442 * capturing a frame. 443 * \param time_in_secs if true time is in seconds, otherwise it is in frames. 422 444 * \param bufferlen Returns size of buffer returned (in bytes). 423 445 * \param video_width Returns width of frame grabbed. 424 446 * \param video_height Returns height of frame grabbed. … … 427 449 * successful, NULL otherwise. 428 450 */ 429 451 char *PreviewGenerator::GetScreenGrab( 430 const ProgramInfo *pginfo, const QString &filename, int secondsin, 452 const ProgramInfo *pginfo, const QString &filename, 453 long long seektime, bool time_in_secs, 431 454 int &bufferlen, 432 455 int &video_width, int &video_height, float &video_aspect) 433 456 { 434 457 (void) pginfo; 435 458 (void) filename; 436 (void) secondsin; 459 (void) seektime; 460 (void) time_in_secs; 437 461 (void) bufferlen; 438 462 (void) video_width; 439 463 (void) video_height; … … 483 507 NuppelVideoPlayer *nvp = new NuppelVideoPlayer(kInUseID, pginfo); 484 508 nvp->SetRingBuffer(rbuf); 485 509 486 retbuf = nvp->GetScreenGrab(secondsin, bufferlen, 487 video_width, video_height, video_aspect); 510 if (time_in_secs) 511 retbuf = nvp->GetScreenGrab(seektime, bufferlen, 512 video_width, video_height, video_aspect); 513 else 514 retbuf = nvp->GetScreenGrabAtFrame( 515 seektime, true, bufferlen, 516 video_width, video_height, video_aspect); 488 517 489 518 delete nvp; 490 519 delete rbuf; … … 493 522 QString msg = "Backend compiled without USING_FRONTEND !!!!"; 494 523 VERBOSE(VB_IMPORTANT, LOC_ERR + msg); 495 524 #endif // USING_FRONTEND 525 526 if (retbuf) 527 { 528 VERBOSE(VB_GENERAL, LOC + 529 QString("Grabbed preview '%0' %1x%2@%3%4") 530 .arg(filename).arg(video_width).arg(video_height) 531 .arg((Q_LLONG)seektime).arg((time_in_secs) ? "s" : "f")); 532 } 533 496 534 return retbuf; 497 535 } 498 536 -
libs/libmythtv/tv_play.cpp
2830 2830 else if ((action == "SCREENSHOT") && (!activerbuffer->isDVD())) 2831 2831 { 2832 2832 long long frameNumber = nvp->GetFramesPlayed(); 2833 int frameWidth = -1;2834 int frameHeight = -1;2835 2833 QString outFile = 2836 2834 QString("%1/.mythtv/%2_%3_%4.png") 2837 2838 2839 2835 .arg(QDir::homeDirPath()).arg(playbackinfo->chanid) 2836 .arg(playbackinfo->recstartts.toString("yyyyMMddhhmmss")) 2837 .arg((long)frameNumber); 2840 2838 2841 PreviewGenerator::SaveScreenshot(playbackinfo, outFile, frameNumber, 2842 frameWidth, frameHeight); 2839 PreviewGenerator *previewgen = new PreviewGenerator(playbackinfo); 2840 previewgen->SetPreviewTimeAsFrameNumber(frameNumber); 2841 previewgen->SetOutputSize(QSize(-1,-1)); 2842 previewgen->SetOutputFilename(outFile); 2843 QString okStr = (previewgen->Run()) ? "" : tr("ERR", "Error"); 2844 previewgen->deleteLater(); 2845 QString msg = tr("Screen Shot") + " " + okStr; 2846 2843 2847 if (activenvp == nvp && GetOSD()) 2844 GetOSD()->SetSettingsText( tr("Screen Shot"), 3);2848 GetOSD()->SetSettingsText(msg, 3); 2845 2849 } 2846 2850 else if (action == "EXITSHOWNOPROMPTS") 2847 2851 { -
libs/libmythtv/previewgenerator.h
14 14 15 15 class MPUBLIC PreviewGenerator : public QObject 16 16 { 17 friend int preview_helper(const QString &chanid, const QString &starttime, 18 long long previewFrameNumber, 19 long long previewSeconds, 20 const QSize &previewSize, 21 const QString &infile, const QString &outfile); 22 17 23 Q_OBJECT 18 24 public: 19 25 PreviewGenerator(const ProgramInfo *pginfo, bool local_only = true); 20 virtual ~PreviewGenerator();21 26 27 void SetPreviewTime(long long time, bool in_seconds) 28 { captureTime = time; timeInSeconds = in_seconds; } 29 void SetPreviewTimeAsSeconds(long long seconds_in) 30 { SetPreviewTime(seconds_in, true); } 31 void SetPreviewTimeAsFrameNumber(long long frame_number) 32 { SetPreviewTime(frame_number, false); } 33 void SetOutputFilename(const QString&); 34 void SetOutputSize(const QSize &size) { outSize = size; } 35 22 36 void Start(void); 23 voidRun(void);37 bool Run(void); 24 38 25 static bool SavePreview(QString filename,26 const unsigned char *data,27 uint width, uint height, float aspect);28 29 static char *GetScreenGrab(const ProgramInfo *pginfo,30 const QString &filename, int secondsin,31 int &bufferlen,32 int &video_width, int &video_height,33 float &video_aspect);34 35 static bool SaveScreenshot(ProgramInfo *pginfo, QString &outFile,36 long long frameNumber,37 int &thumbWidth, int &thumbHeight);38 39 39 void AttachSignals(QObject*); 40 40 void disconnectSafe(void); 41 41 … … 48 48 void deleteLater(); 49 49 50 50 private: 51 virtual ~PreviewGenerator(); 52 bool RunReal(void); 53 54 static char *GetScreenGrab(const ProgramInfo *pginfo, 55 const QString &filename, 56 long long seektime, bool time_in_secs, 57 int &bufferlen, 58 int &video_width, int &video_height, 59 float &video_aspect); 60 61 static bool SavePreview(QString filename, 62 const unsigned char *data, 63 uint width, uint height, float aspect, 64 int desired_width, int desired_height); 65 51 66 void TeardownAll(void); 52 67 bool RemotePreviewSetup(void); 53 voidRemotePreviewRun(void);68 bool RemotePreviewRun(void); 54 69 void RemotePreviewTeardown(void); 55 voidLocalPreviewRun(void);70 bool LocalPreviewRun(void); 56 71 bool IsLocal(void) const; 57 72 static void *PreviewRun(void*); 58 73 … … 65 80 bool createSockets; 66 81 MythSocket *serverSock; 67 82 QString pathname; 83 84 /// tells us whether to use time as seconds or frame number 85 bool timeInSeconds; 86 /// snapshot time in seconds or frame number, depending on timeInSeconds 87 long long captureTime; 88 QString outFileName; 89 QSize outSize; 68 90 }; 69 91 70 92 #endif // PREVIEW_GENERATOR_H_ -
programs/mythfrontend/playbackbox.cpp
22 22 #include <unistd.h> 23 23 #include <stdlib.h> 24 24 25 #include <algorithm> 25 26 #include <iostream> 26 27 using namespace std; 27 28 … … 54 55 55 56 QWaitCondition pbbIsVisibleCond; 56 57 58 const uint PreviewGenState::maxAttempts = 5; 59 const uint PreviewGenState::minBlockSeconds = 60; 60 61 const uint PlaybackBox::previewGeneratorMaxRunning = 2; 62 57 63 static int comp_programid(ProgramInfo *a, ProgramInfo *b) 58 64 { 59 65 if (a->programid == b->programid) … … 273 279 // Preview Image Variables 274 280 previewPixmapEnabled(false), previewPixmap(NULL), 275 281 previewSuspend(false), previewChanid(""), 282 previewGeneratorRunning(0), 276 283 // Network Control Variables 277 284 underNetworkControl(false), 278 285 m_player(NULL) … … 470 477 471 478 // disconnect preview generators 472 479 QMutexLocker locker(&previewGeneratorLock); 473 QMap<QString, PreviewGenerator*>::iterator it = previewGenerator.begin();480 PreviewMap::iterator it = previewGenerator.begin(); 474 481 for (;it != previewGenerator.end(); ++it) 475 482 { 476 if ( *it)477 (*it) ->disconnectSafe();483 if ((*it).gen) 484 (*it).gen->disconnectSafe(); 478 485 } 479 486 480 487 // free preview pixmap after preview generators are … … 4238 4245 return datetime; 4239 4246 } 4240 4247 4248 void PlaybackBox::IncPreviewGeneratorPriority(const QString &xfn) 4249 { 4250 QString fn = QDeepCopy<QString>(xfn.mid(max(xfn.findRev('/') + 1,0))); 4251 4252 QMutexLocker locker(&previewGeneratorLock); 4253 vector<QString> &q = previewGeneratorQueue; 4254 vector<QString>::iterator it = std::find(q.begin(), q.end(), fn); 4255 if (it != q.end()) 4256 q.erase(it); 4257 4258 PreviewMap::iterator pit = previewGenerator.find(fn); 4259 if (pit != previewGenerator.end() && (*pit).gen && !(*pit).genStarted) 4260 q.push_back(fn); 4261 } 4262 4263 void PlaybackBox::UpdatePreviewGeneratorThreads(void) 4264 { 4265 QMutexLocker locker(&previewGeneratorLock); 4266 vector<QString> &q = previewGeneratorQueue; 4267 if ((previewGeneratorRunning < previewGeneratorMaxRunning) && q.size()) 4268 { 4269 QString fn = q.back(); 4270 q.pop_back(); 4271 PreviewMap::iterator it = previewGenerator.find(fn); 4272 if (it != previewGenerator.end() && (*it).gen && !(*it).genStarted) 4273 { 4274 previewGeneratorRunning++; 4275 (*it).gen->Start(); 4276 (*it).genStarted = true; 4277 } 4278 } 4279 } 4280 4241 4281 /** \fn PlaybackBox::SetPreviewGenerator(const QString&, PreviewGenerator*) 4242 4282 * \brief Sets the PreviewGenerator for a specific file. 4243 4283 * \return true iff call succeeded. 4244 4284 */ 4245 4285 bool PlaybackBox::SetPreviewGenerator(const QString &xfn, PreviewGenerator *g) 4246 4286 { 4247 QString fn = xfn.mid(max(xfn.findRev('/') + 1,0)); 4287 QString fn = QDeepCopy<QString>(xfn.mid(max(xfn.findRev('/') + 1,0))); 4288 QMutexLocker locker(&previewGeneratorLock); 4289 4248 4290 if (!g) 4249 4291 { 4250 if (previewGeneratorLock.tryLock()) 4251 { 4252 previewGenerator.erase(fn); 4253 previewGeneratorLock.unlock(); 4254 return true; 4255 } 4256 return false; 4292 previewGeneratorRunning = max(0, (int)previewGeneratorRunning - 1); 4293 PreviewMap::iterator it = previewGenerator.find(fn); 4294 if (it == previewGenerator.end()) 4295 return false; 4296 4297 (*it).gen = NULL; 4298 (*it).genStarted = false; 4299 (*it).ready = false; 4300 (*it).lastBlockTime = 4301 max(PreviewGenState::minBlockSeconds, (*it).lastBlockTime * 2); 4302 (*it).blockRetryUntil = 4303 QDateTime::currentDateTime().addSecs((*it).lastBlockTime); 4304 4305 return true; 4257 4306 } 4258 4307 4259 QMutexLocker locker(&previewGeneratorLock);4260 4308 g->AttachSignals(this); 4261 previewGenerator[fn] = g; 4262 g->Start(); 4309 previewGenerator[fn].gen = g; 4310 previewGenerator[fn].genStarted = false; 4311 previewGenerator[fn].ready = false; 4263 4312 4313 previewGeneratorLock.unlock(); 4314 IncPreviewGeneratorPriority(xfn); 4315 previewGeneratorLock.lock(); 4316 4264 4317 return true; 4265 4318 } 4266 4319 4267 /** \fn PlaybackBox::IsGeneratingPreview(const QString& ) const4320 /** \fn PlaybackBox::IsGeneratingPreview(const QString&, bool) const 4268 4321 * \brief Returns true if we have already started a 4269 4322 * PreviewGenerator to create this file. 4270 4323 */ 4271 bool PlaybackBox::IsGeneratingPreview(const QString &xfn ) const4324 bool PlaybackBox::IsGeneratingPreview(const QString &xfn, bool really) const 4272 4325 { 4273 QMap<QString, PreviewGenerator*>::const_iterator it;4326 PreviewMap::const_iterator it; 4274 4327 QMutexLocker locker(&previewGeneratorLock); 4275 4328 4276 4329 QString fn = xfn.mid(max(xfn.findRev('/') + 1,0)); 4277 4330 if ((it = previewGenerator.find(fn)) == previewGenerator.end()) 4278 4331 return false; 4279 return *it; 4332 4333 if (really) 4334 return ((*it).gen && !(*it).ready); 4335 4336 if ((*it).blockRetryUntil.isValid()) 4337 return QDateTime::currentDateTime() < (*it).blockRetryUntil; 4338 4339 return (*it).gen; 4280 4340 } 4281 4341 4282 4342 /** \fn PlaybackBox::IncPreviewGeneratorAttempts(const QString&) … … 4287 4347 { 4288 4348 QMutexLocker locker(&previewGeneratorLock); 4289 4349 QString fn = xfn.mid(max(xfn.findRev('/') + 1,0)); 4290 return previewGenerator Attempts[fn]++;4350 return previewGenerator[fn].attempts++; 4291 4351 } 4292 4352 4293 4353 void PlaybackBox::previewThreadDone(const QString &fn, bool &success) 4294 4354 { 4295 4355 success = SetPreviewGenerator(fn, NULL); 4356 UpdatePreviewGeneratorThreads(); 4296 4357 } 4297 4358 4298 4359 /** \fn PlaybackBox::previewReady(const ProgramInfo*) … … 4302 4363 */ 4303 4364 void PlaybackBox::previewReady(const ProgramInfo *pginfo) 4304 4365 { 4366 QString xfn = pginfo->pathname + ".png"; 4367 QString fn = xfn.mid(max(xfn.findRev('/') + 1,0)); 4368 4369 previewGeneratorLock.lock(); 4370 PreviewMap::iterator it = previewGenerator.find(fn); 4371 if (it != previewGenerator.end()) 4372 { 4373 (*it).ready = true; 4374 (*it).attempts = 0; 4375 (*it).lastBlockTime = 0; 4376 } 4377 previewGeneratorLock.unlock(); 4378 4305 4379 // lock QApplication so that we don't remove pixmap 4306 4380 // from under a running paint event. 4307 4381 qApp->lock(); … … 4356 4430 if (check_date) 4357 4431 previewLastModified = getPreviewLastModified(pginfo); 4358 4432 4433 IncPreviewGeneratorPriority(filename); 4434 4359 4435 if (previewFromBookmark && 4360 4436 check_date && 4361 4437 (!previewLastModified.isValid() || … … 4381 4457 .arg(!IsGeneratingPreview(filename))); 4382 4458 4383 4459 uint attempts = IncPreviewGeneratorAttempts(filename); 4384 if (attempts < 5)4460 if (attempts < PreviewGenState::maxAttempts) 4385 4461 { 4386 #ifdef USE_PREV_GEN_THREAD4387 4462 SetPreviewGenerator(filename, new PreviewGenerator(pginfo, false)); 4388 #else4389 PreviewGenerator pg(pginfo, false);4390 pg.Run();4391 #endif4392 4463 } 4393 else if (attempts == 5)4464 else if (attempts == PreviewGenState::maxAttempts) 4394 4465 { 4395 4466 VERBOSE(VB_IMPORTANT, LOC_ERR + 4396 QString("Attempted to generate preview for '%1'") 4397 .arg(filename) + " 5 times, giving up."); 4467 QString("Attempted to generate preview for '%1' " 4468 "%2 times, giving up.") 4469 .arg(filename).arg(PreviewGenState::maxAttempts)); 4398 4470 } 4399 4471 4400 if (attempts >= 5)4472 if (attempts >= PreviewGenState::maxAttempts) 4401 4473 return retpixmap; 4402 4474 } 4403 4475 4476 UpdatePreviewGeneratorThreads(); 4477 4404 4478 // Check and see if we've already tried this one. 4405 4479 if (previewPixmap && 4406 4480 pginfo->recstartts == previewStartts && … … 4436 4510 //if this is a remote frontend, then we need to refresh the pixmap 4437 4511 //if another frontend has already regenerated the stale pixmap on the disk 4438 4512 bool refreshPixmap = (previewLastModified >= previewFilets); 4439 bool generating_preview = IsGeneratingPreview(filename);4440 4513 4441 4514 QImage *image = NULL; 4442 if (! generating_preview)4515 if (!IsGeneratingPreview(filename, true)) 4443 4516 image = gContext->CacheRemotePixmap(filename, refreshPixmap); 4444 4517 4445 4518 // If the image is not available remotely either, we need to generate it. 4446 if (!image && ! generating_preview)4519 if (!image && !IsGeneratingPreview(filename)) 4447 4520 { 4448 #ifdef USE_PREV_GEN_THREAD4449 4521 uint attempts = IncPreviewGeneratorAttempts(filename); 4450 if (attempts < 5)4522 if (attempts < PreviewGenState::maxAttempts) 4451 4523 { 4452 4524 VERBOSE(VB_PLAYBACK, "Starting preview generator"); 4453 4525 SetPreviewGenerator(filename, new PreviewGenerator(pginfo, false)); 4454 4526 } 4455 else if (attempts == 5)4527 else if (attempts == PreviewGenState::maxAttempts) 4456 4528 { 4457 4529 VERBOSE(VB_IMPORTANT, LOC_ERR + 4458 QString("Attempted to generate preview for '%1'") 4459 .arg(filename) + " 5 times, giving up."); 4530 QString("Attempted to generate preview for '%1' " 4531 "%2 times, giving up.") 4532 .arg(filename).arg(PreviewGenState::maxAttempts)); 4533 4460 4534 return retpixmap; 4461 4535 } 4462 #else4463 PreviewGenerator pg(pginfo, false);4464 pg.Run();4465 image = gContext->CacheRemotePixmap(filename, true);4466 #endif4467 4536 } 4468 4537 4469 4538 if (image) -
programs/mythfrontend/playbackbox.h
3 3 #ifndef PLAYBACKBOX_H_ 4 4 #define PLAYBACKBOX_H_ 5 5 6 // C++ headers 7 #include <vector> 8 using namespace std; 9 6 10 #include <qdatetime.h> 7 11 #include <qdom.h> 8 12 #include <qmutex.h> … … 29 33 30 34 class LayerSet; 31 35 36 class PreviewGenState 37 { 38 public: 39 PreviewGenState() : 40 gen(NULL), genStarted(false), ready(false), 41 attempts(0), lastBlockTime(0) {} 42 PreviewGenerator *gen; 43 bool genStarted; 44 bool ready; 45 uint attempts; 46 uint lastBlockTime; 47 QDateTime blockRetryUntil; 48 49 static const uint maxAttempts; 50 static const uint minBlockSeconds; 51 }; 52 32 53 typedef QMap<QString,ProgramList> ProgramMap; 33 54 typedef QMap<QString,QString> Str2StrMap; 34 typedef QMap<QString,PreviewGen erator*>PreviewMap;55 typedef QMap<QString,PreviewGenState> PreviewMap; 35 56 typedef QMap<QString,MythTimer> LastCheckedMap; 36 57 37 58 class PlaybackBox : public MythDialog … … 238 259 void keyPressEvent(QKeyEvent *e); 239 260 240 261 bool SetPreviewGenerator(const QString &fn, PreviewGenerator *g); 241 bool IsGeneratingPreview(const QString &fn) const; 262 void IncPreviewGeneratorPriority(const QString &fn); 263 void UpdatePreviewGeneratorThreads(void); 264 bool IsGeneratingPreview(const QString &fn, bool really = false) const; 242 265 uint IncPreviewGeneratorAttempts(const QString &fn); 243 266 244 267 void SetRecGroupPassword(const QString &oldPasswd, … … 462 485 QString previewChanid; 463 486 mutable QMutex previewGeneratorLock; 464 487 PreviewMap previewGenerator; 465 QMap<QString,uint> previewGeneratorAttempts; 488 vector<QString> previewGeneratorQueue; 489 uint previewGeneratorRunning; 490 static const uint previewGeneratorMaxRunning; 466 491 467 492 // Network Control Variables ////////////////////////////////////////////// 468 493 mutable QMutex ncLock; -
programs/mythfrontend/networkcontrol.cpp
979 979 980 980 frameNumber = results[7].toInt(); 981 981 982 bool res = PreviewGenerator::SaveScreenshot(pginfo, outFile, 983 frameNumber, width, height); 982 PreviewGenerator *previewgen = new PreviewGenerator(pginfo); 983 previewgen->SetPreviewTimeAsFrameNumber(frameNumber); 984 previewgen->SetOutputFilename(outFile); 985 previewgen->SetOutputSize(QSize(width, height)); 986 previewgen->Run(); 987 previewgen->deleteLater(); 988 984 989 delete pginfo; 985 990 986 if (res)987 return QString("OK %1x%2").arg(width ).arg(height);988 else989 return "ERROR: Unable to generate screenshot, check logs";991 // if (res) 992 return QString("OK %1x%2").arg(width>0?width:64).arg(height>0?height:64); 993 // else 994 // return "ERROR: Unable to generate screenshot, check logs"; 990 995 } 991 996 else 992 997 return "ERROR: Timed out waiting for reply from player"; -
programs/mythbackend/mythxml.cpp
4 4 // Purpose - Html & XML status HttpServerExtension 5 5 // 6 6 // Created By : David Blain Created On : Oct. 24, 2005 7 // Modified By : Modified On:7 // Modified By : Daniel Kristjansson Modified On: Oct. 31, 2007 8 8 // 9 9 ////////////////////////////////////////////////////////////////////////////// 10 10 … … 15 15 #include "libmyth/util.h" 16 16 #include "libmyth/mythdbcon.h" 17 17 18 #include "previewgenerator.h" 18 19 #include "backendutil.h" 19 20 20 21 #include <qtextstream.h> … … 973 974 974 975 // ---------------------------------------------------------------------- 975 976 976 if ((nWidth == 0) && (nHeight == 0)) 977 { 978 bDefaultPixmap = true; 979 nWidth = gContext->GetNumSetting("PreviewPixmapWidth", 160); 980 nHeight = gContext->GetNumSetting("PreviewPixmapHeight", 120); 981 } 977 bDefaultPixmap = (nWidth == 0) && (nHeight == 0) && (nSecsIn >= 0); 982 978 983 979 // ---------------------------------------------------------------------- 984 // Determine Time the image should be extracted from985 // ----------------------------------------------------------------------986 987 if (nSecsIn == 0)988 {989 nSecsIn = gContext->GetNumSetting("PreviewPixmapOffset", 64) +990 gContext->GetNumSetting("RecordPreRoll",0);991 }992 993 // ----------------------------------------------------------------------994 980 // If a specific size/time is requested, don't use cached image. 995 981 // ---------------------------------------------------------------------- 996 982 // -=>TODO: should cache custom sized images... … … 1023 1009 // Must generate Preview Image, Generate Image and save. 1024 1010 // ------------------------------------------------------------------ 1025 1011 1026 float fAspect = 0.0; 1027 1028 QImage *pImage = GeneratePreviewImage( pInfo, 1029 sFileName, 1030 nSecsIn, 1031 fAspect ); 1032 1033 if (pImage == NULL) 1012 PreviewGenerator *previewgen = new PreviewGenerator(pInfo, true); 1013 previewgen->SetPreviewTimeAsSeconds(nSecsIn); 1014 previewgen->SetOutputFilename(pRequest->m_sFileName); 1015 previewgen->SetOutputSize(QSize(nWidth, nHeight)); 1016 bool ok = previewgen->Run(); 1017 if (ok) 1034 1018 { 1035 delete pInfo;1036 return;1019 pRequest->m_eResponseType = ResponseTypeFile; 1020 pRequest->m_nResponseStatus = 200; 1037 1021 } 1038 1039 // ------------------------------------------------------------------ 1040 1041 if (bDefaultPixmap) 1042 { 1043 1044 if (fAspect <= 0) 1045 fAspect = (float)(nWidth) / nHeight; 1046 1047 if (fAspect > nWidth / nHeight) 1048 nHeight = (int)rint(nWidth / fAspect); 1049 else 1050 nWidth = (int)rint(nHeight * fAspect); 1051 } 1052 else 1053 { 1054 if ( nWidth == 0 ) 1055 nWidth = (int)rint(nHeight * fAspect); 1056 1057 if ( nHeight == 0 ) 1058 nHeight = (int)rint(nWidth / fAspect); 1059 1060 /* 1061 QByteArray aBytes; 1062 QBuffer buffer( aBytes ); 1063 1064 buffer.open( IO_WriteOnly ); 1065 img.save( &buffer, "PNG" ); 1066 1067 pRequest->m_eResponseType = ResponseTypeOther; 1068 pRequest->m_sResponseTypeText = pRequest->GetMimeType( "png" ); 1069 pRequest->m_nResponseStatus = 200; 1070 1071 pRequest->m_response.writeRawBytes( aBytes.data(), aBytes.size() ); 1072 */ 1073 } 1074 1075 QImage img = pImage->smoothScale( nWidth, nHeight); 1076 1077 img.save( pRequest->m_sFileName.ascii(), "PNG" ); 1078 1079 delete pImage; 1080 1081 if (pInfo) 1082 delete pInfo; 1083 1084 pRequest->m_eResponseType = ResponseTypeFile; 1085 pRequest->m_nResponseStatus = 200; 1022 previewgen->deleteLater(); 1086 1023 } 1087 1024 1088 1025 ///////////////////////////////////////////////////////////////////////////// 1089 1026 // 1090 1027 ///////////////////////////////////////////////////////////////////////////// 1091 1028 1092 QImage *MythXML::GeneratePreviewImage( ProgramInfo *pInfo,1093 const QString &sFileName,1094 int nSecsIn,1095 float &fAspect )1096 {1097 1098 // Find first Local encoder1099 1100 EncoderLink *pEncoder = NULL;1101 1102 for ( QMap<int, EncoderLink *>::Iterator it = m_pEncoders->begin();1103 it != m_pEncoders->end();1104 ++it )1105 {1106 if (it.data()->IsLocal())1107 {1108 pEncoder = it.data();1109 break;1110 }1111 }1112 1113 if ( pEncoder == NULL)1114 return NULL;1115 1116 // ------------------------------------------------------------------1117 // Generate Preview Image and save.1118 // ------------------------------------------------------------------1119 1120 int nLen = 0, nWidth = 0, nHeight = 0;1121 1122 unsigned char *pData = (unsigned char *)pEncoder->GetScreenGrab( pInfo,1123 sFileName,1124 nSecsIn,1125 nLen,1126 nWidth,1127 nHeight,1128 fAspect);1129 if (!pData)1130 return NULL;1131 1132 return new QImage( pData, nWidth, nHeight, 32, NULL, 65536 * 65536, QImage::LittleEndian );1133 }1134 1135 /////////////////////////////////////////////////////////////////////////////1136 //1137 /////////////////////////////////////////////////////////////////////////////1138 1139 1029 void MythXML::GetRecording( HttpWorkerThread *pThread, 1140 1030 HTTPRequest *pRequest ) 1141 1031 { -
programs/mythbackend/main.cpp
1 #include <sys/time.h> // for setpriority 2 #include <sys/resource.h> // for setpriority 3 1 4 #include <qapplication.h> 2 5 #include <qsqldatabase.h> 3 6 #include <qfile.h> … … 36 39 #include "libmythtv/dbcheck.h" 37 40 #include "libmythtv/jobqueue.h" 38 41 #include "libmythtv/storagegroup.h" 42 #include "libmythtv/previewgenerator.h" 39 43 40 44 #include "mediaserver.h" 41 45 #include "httpstatus.h" … … 245 249 log_rotate(0); 246 250 } 247 251 252 int preview_helper(const QString &chanid, const QString &starttime, 253 long long previewFrameNumber, long long previewSeconds, 254 const QSize &previewSize, 255 const QString &infile, const QString &outfile) 256 { 257 // Lower scheduling priority, to avoid problems with recordings. 258 if (setpriority(PRIO_PROCESS, 0, 9)) 259 VERBOSE(VB_GENERAL, "Setting priority failed." + ENO); 248 260 261 ProgramInfo *pginfo = NULL; 262 if (!chanid.isEmpty() && !starttime.isEmpty()) 263 { 264 pginfo = ProgramInfo::GetProgramFromRecorded(chanid, starttime); 265 if (!pginfo) 266 { 267 VERBOSE(VB_IMPORTANT, QString( 268 "Can not locate recording made on '%1' at '%2'") 269 .arg(chanid).arg(starttime)); 270 return GENERIC_EXIT_NOT_OK; 271 } 272 } 273 else if (!infile.isEmpty()) 274 { 275 pginfo = ProgramInfo::GetProgramFromBasename(infile); 276 if (!pginfo) 277 { 278 VERBOSE(VB_IMPORTANT, QString( 279 "Can not locate recording '%1'").arg(infile)); 280 return GENERIC_EXIT_NOT_OK; 281 } 282 } 283 else 284 { 285 VERBOSE(VB_IMPORTANT, "Can not locate for preview"); 286 return GENERIC_EXIT_NOT_OK; 287 } 288 289 PreviewGenerator *previewgen = new PreviewGenerator(pginfo, true); 290 291 if (previewFrameNumber >= 0) 292 previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber); 293 294 if (previewSeconds >= 0) 295 previewgen->SetPreviewTimeAsSeconds(previewSeconds); 296 297 previewgen->SetOutputSize(previewSize); 298 previewgen->SetOutputFilename(outfile); 299 previewgen->RunReal(); 300 previewgen->deleteLater(); 301 302 delete pginfo; 303 304 return GENERIC_EXIT_OK; 305 } 306 307 // [WxH] | [WxH@]seconds[S] | [WxH@]frame_numF 308 bool parse_preview_info(const QString ¶m, 309 long long &previewFrameNumber, 310 long long &previewSeconds, 311 QSize &previewSize) 312 { 313 previewFrameNumber = -1; 314 previewSeconds = -1; 315 previewSize = QSize(0,0); 316 if (param.isEmpty()) 317 return true; 318 319 int xat = param.find("x", 0, false); 320 int aat = param.find("@", 0, false); 321 if (xat > 0) 322 { 323 QString widthStr = param.left(xat); 324 QString heightStr = QString::null; 325 if (aat > xat) 326 heightStr = param.mid(xat + 1, aat - xat - 1); 327 else 328 heightStr = param.mid(xat + 1); 329 330 bool ok1, ok2; 331 previewSize = QSize(widthStr.toInt(&ok1), heightStr.toInt(&ok2)); 332 if (!ok1 || !ok2) 333 { 334 VERBOSE(VB_IMPORTANT, QString( 335 "Error: Failed to parse --generate-preview " 336 "param '%1'").arg(param)); 337 } 338 } 339 if ((xat > 0) && (aat < xat)) 340 return true; 341 342 QString lastChar = param.at(param.length() - 1).lower(); 343 QString frameNumStr = QString::null; 344 QString secsStr = QString::null; 345 if (lastChar == "f") 346 frameNumStr = param.mid(aat + 1, param.length() - aat - 2); 347 else if (lastChar == "s") 348 secsStr = param.mid(aat + 1, param.length() - aat - 2); 349 else 350 secsStr = param.mid(aat + 1, param.length() - aat - 1); 351 352 bool ok = false; 353 if (!frameNumStr.isEmpty()) 354 previewFrameNumber = frameNumStr.toUInt(&ok); 355 else if (!secsStr.isEmpty()) 356 previewSeconds = secsStr.toUInt(&ok); 357 358 if (!ok) 359 { 360 VERBOSE(VB_IMPORTANT, QString( 361 "Error: Failed to parse --generate-preview " 362 "param '%1'").arg(param)); 363 } 364 365 return ok; 366 } 367 249 368 int main(int argc, char **argv) 250 369 { 251 370 for(int i = 3; i < sysconf(_SC_OPEN_MAX) - 1; ++i) … … 256 375 QMap<QString, QString> settingsOverride; 257 376 QString binname = basename(a.argv()[0]); 258 377 378 long long previewFrameNumber = -2; 379 long long previewSeconds = -2; 380 QSize previewSize(0,0); 381 QString chanid = QString::null; 382 QString starttime = QString::null; 383 QString infile = QString::null; 384 QString outfile = QString::null; 385 259 386 bool daemonize = false; 260 387 bool printsched = false; 261 388 bool testsched = false; … … 417 544 #endif 418 545 return BACKEND_EXIT_OK; 419 546 } 547 else if (!strcmp(a.argv()[argpos],"--generate-preview")) 548 { 549 QString tmp = QString::null; 550 if ((argpos + 1) < a.argc()) 551 { 552 tmp = a.argv()[argpos+1]; 553 bool ok = true; 554 if (tmp.left(1) == "-") 555 tmp.left(2).toInt(&ok); 556 if (ok) 557 argpos++; 558 else 559 tmp = QString::null; 560 } 561 562 if (!parse_preview_info(tmp, previewFrameNumber, previewSeconds, 563 previewSize)) 564 { 565 VERBOSE(VB_IMPORTANT, 566 QString("Unable to parse --generate-preview option '%1'") 567 .arg(tmp)); 568 return BACKEND_EXIT_INVALID_CMDLINE; 569 } 570 } 571 else if (!strcmp(a.argv()[argpos],"-c") || 572 !strcmp(a.argv()[argpos],"--chanid")) 573 { 574 if (((argpos + 1) >= a.argc()) || 575 !strncmp(a.argv()[argpos + 1], "-", 1)) 576 { 577 VERBOSE(VB_IMPORTANT, 578 "Missing or invalid parameters for --chanid option"); 579 return BACKEND_EXIT_INVALID_CMDLINE; 580 } 581 582 chanid = a.argv()[++argpos]; 583 } 584 else if (!strcmp(a.argv()[argpos],"-s") || 585 !strcmp(a.argv()[argpos],"--starttime")) 586 { 587 if (((argpos + 1) >= a.argc()) || 588 !strncmp(a.argv()[argpos + 1], "-", 1)) 589 { 590 VERBOSE(VB_IMPORTANT, 591 "Missing or invalid parameters for --starttime option"); 592 return BACKEND_EXIT_INVALID_CMDLINE; 593 } 594 595 starttime = a.argv()[++argpos]; 596 } 597 else if (!strcmp(a.argv()[argpos],"--infile")) 598 { 599 if (((argpos + 1) >= a.argc()) || 600 !strncmp(a.argv()[argpos + 1], "-", 1)) 601 { 602 VERBOSE(VB_IMPORTANT, 603 "Missing or invalid parameters for --infile option"); 604 return BACKEND_EXIT_INVALID_CMDLINE; 605 } 606 607 infile = a.argv()[++argpos]; 608 } 609 else if (!strcmp(a.argv()[argpos],"--outfile")) 610 { 611 if (((argpos + 1) >= a.argc()) || 612 !strncmp(a.argv()[argpos + 1], "-", 1)) 613 { 614 VERBOSE(VB_IMPORTANT, 615 "Missing or invalid parameters for --outfile option"); 616 return BACKEND_EXIT_INVALID_CMDLINE; 617 } 618 619 outfile = a.argv()[++argpos]; 620 } 420 621 else 421 622 { 422 623 if (!(!strcmp(a.argv()[argpos],"-h") || … … 439 640 "--nohousekeeper Do not start the Housekeeper" << endl << 440 641 "--noautoexpire Do not start the AutoExpire thread" << endl << 441 642 "--clearcache Clear the settings cache on all myth servers" << endl << 442 "--version Version information" << endl; 643 "--version Version information" << endl << 644 "--generate-preview " << endl; 443 645 return BACKEND_EXIT_INVALID_CMDLINE; 444 646 } 445 647 } 446 648 649 if (((previewFrameNumber >= -1) || previewSeconds >= -1) && 650 (chanid.isEmpty() || starttime.isEmpty()) && infile.isEmpty()) 651 { 652 cerr << "--generate-preview must be accompanied by either " <<endl 653 << "\nboth --chanid and --starttime paramaters, " << endl 654 << "\nor the --infile paramater." << endl; 655 return BACKEND_EXIT_INVALID_CMDLINE; 656 } 657 447 658 if (logfile != "" ) 448 659 { 449 660 if (log_rotate(1) < 0) … … 576 787 return BACKEND_EXIT_OK; 577 788 } 578 789 790 if ((previewFrameNumber >= -1) || (previewSeconds >= -1)) 791 { 792 preview_helper(chanid, starttime, 793 previewFrameNumber, previewSeconds, previewSize, 794 infile, outfile); 795 return BACKEND_EXIT_OK; 796 } 797 579 798 int port = gContext->GetNumSetting("BackendServerPort", 6543); 580 799 581 800 QString myip = gContext->GetSetting("BackendServerIP"); -
programs/mythbackend/encoderlink.h
103 103 QString callsign, QString channum, 104 104 QString channame, QString xmltv); 105 105 106 char *GetScreenGrab(const ProgramInfo *pginfo, const QString &filename,107 int secondsin, int &bufferlen,108 int &video_width, int &video_height,109 float &video_aspect);110 111 106 private: 112 107 int m_capturecardnum; 113 108 -
programs/mythbackend/mythxml.h
104 104 void GetConnectionInfo( HTTPRequest *pRequest ); 105 105 void GetAlbumArt ( HTTPRequest *pRequest ); 106 106 107 QImage *GeneratePreviewImage( ProgramInfo *pInfo,108 const QString &sFileName,109 int nSecsIn,110 float &fAspect );111 112 107 void GetExpiring ( HTTPRequest *pRequest ); 113 108 114 109 void GetRecording ( HttpWorkerThread *pThread, -
programs/mythbackend/mainserver.cpp
3694 3694 return; 3695 3695 } 3696 3696 3697 int len = 0; 3698 int width = 0, height = 0; 3699 float aspect = 0; 3700 int secondsin = gContext->GetNumSetting("PreviewPixmapOffset", 64) + 3701 gContext->GetNumSetting("RecordPreRoll",0); 3697 PreviewGenerator *previewgen = new PreviewGenerator(pginfo); 3698 bool ok = previewgen->Run(); 3699 previewgen->deleteLater(); 3702 3700 3703 unsigned char *data = (unsigned char *) 3704 PreviewGenerator::GetScreenGrab(pginfo, pginfo->pathname, secondsin, 3705 len, width, height, aspect); 3706 3707 if (data && PreviewGenerator::SavePreview(pginfo->pathname + ".png", data, 3708 width, height, aspect)) 3701 if (ok) 3709 3702 { 3710 3703 QStringList retlist = "OK"; 3711 3704 SendResponse(pbssock, retlist); … … 3717 3710 SendResponse(pbssock, outputlist); 3718 3711 } 3719 3712 3720 if (data)3721 delete [] data;3722 3713 delete pginfo; 3723 3714 } 3724 3715 -
programs/mythbackend/encoderlink.cpp
836 836 callsign, channum, channame, xmltv); 837 837 } 838 838 839 /** \fn EncoderLink::GetScreenGrab(const ProgramInfo*,const QString&,int,int&,int&,int&,float&)840 * \brief Returns a PIX_FMT_RGBA32 buffer containg a frame from the video.841 * <b>This only works on local recorders.</b>842 * \param pginfo Recording to grab from.843 * \param filename File containing recording.844 * \param secondsin Seconds into the video to seek before capturing a frame.845 * \param bufferlen Returns size of buffer returned (in bytes).846 * \param video_width Returns width of frame grabbed.847 * \param video_height Returns height of frame grabbed.848 * \param video_aspect Returns the aspect ratio of frame grabbed.849 * \return Buffer allocated with new containing frame in RGBA32 format if850 * successful, NULL otherwise.851 */852 char *EncoderLink::GetScreenGrab(const ProgramInfo *pginfo,853 const QString &filename,854 int secondsin, int &bufferlen,855 int &video_width, int &video_height,856 float &video_aspect)857 {858 if (local)859 {860 return PreviewGenerator::GetScreenGrab(861 pginfo, filename, secondsin, bufferlen,862 video_width, video_height, video_aspect);863 }864 VERBOSE(VB_IMPORTANT, "Should be local only query: GetScreenGrab");865 return NULL;866 }867 868 839 /* vim: set expandtab tabstop=4 shiftwidth=4: */