Go to the documentation of this file.
35 #include <QApplication>
37 #include <QDomDocument>
42 #include <mythconfig.h>
59 #include <libavutil/imgutils.h>
62 #ifndef INT64_C // Used in FFmpeg headers to define some constants
63 #define INT64_C(v) (v ## LL)
86 const QString &menuTheme)
88 m_archiveItem(archiveItem),
89 m_thumbCount(getChapterCount(menuTheme)),
90 m_thumbDir(createThumbDir())
135 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'mythburn'");
164 for (
int i = 0; i < actions.size() && !handled; i++)
166 QString
action = actions[i];
199 else if (
action ==
"DOWN")
203 else if (
action ==
"LEFT")
207 else if (
action ==
"RIGHT")
211 else if (
action ==
"SELECT")
231 menuTheme +
"/theme.xml";
232 QDomDocument doc(
"mydocument");
235 if (!
file.open(QIODevice::ReadOnly))
237 LOG(VB_GENERAL, LOG_ERR,
"Failed to open theme file: " +
filename);
240 if (!doc.setContent(&
file))
243 LOG(VB_GENERAL, LOG_ERR,
"Failed to parse theme file: " +
filename);
248 QDomNodeList chapterNodeList = doc.elementsByTagName(
"chapter");
250 return chapterNodeList.count();
263 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder::loadCutList: Got an empty delete map");
268 frm_dir_map_t::const_iterator it =
m_deleteMap.constBegin();
351 if( chmod(qPrintable(thumbDir), 0777) != 0 )
352 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: Failed to change permissions"
353 " on thumb directory: " +
ENO);
357 for (
int x = 1; dir.exists(); x++)
359 path = thumbDir + QString(
"/%1").arg(x);
364 if( chmod(qPrintable(path), 0777) != 0 )
365 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: Failed to change permissions on "
366 "thumb directory: %1" +
ENO);
381 QString imageFile = thumb->
filename;
382 QFile dst(imageFile);
386 item->
SetImage(imageFile,
"",
true);
402 int sec = (int) (frame /
m_fps);
403 frame = frame - (int) (sec *
m_fps);
407 str += QString(
".%1").arg(frame,10,2,QChar(
'0'));
415 LOG(VB_GENERAL, LOG_ERR,
416 QString(
"ThumbFinder:: Failed to get file details for %1")
458 thumb->
frame = (int64_t) 0;
470 QCoreApplication::processEvents();
486 int chapter = chapterLen * (x - 1);
487 int hour = chapter / 3600;
488 int min = (chapter % 3600) / 60;
489 int sec = chapter % 60;
490 QString time = QString::asprintf(
"%02d:%02d:%02d", hour, min, sec);
492 auto frame = (int64_t) (chapter * ceil(
m_fps));
497 thumb->
frame = frame;
505 QCoreApplication::processEvents();
507 QCoreApplication::processEvents();
509 QCoreApplication::processEvents();
527 LOG(VB_JOBQUEUE, LOG_INFO, QString(
"ThumbFinder: Opening '%1'")
532 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder, Couldn't open input file" +
ENO);
537 int ret = avformat_find_stream_info(
m_inputFC,
nullptr);
540 LOG(VB_GENERAL, LOG_ERR,
541 QString(
"Couldn't get stream info, error #%1").arg(ret));
545 av_dump_format(
m_inputFC, 0, qPrintable(inFile), 0);
553 if (
m_inputFC->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
556 if (
m_inputFC->streams[i]->start_time != (
int) AV_NOPTS_VALUE)
560 LOG(VB_GENERAL, LOG_ERR,
561 "ThumbFinder: Failed to get start time");
568 if (st->r_frame_rate.den && st->r_frame_rate.num)
569 m_fps = av_q2d(st->r_frame_rate);
571 m_fps = 1/av_q2d(st->time_base);
578 LOG(VB_GENERAL, LOG_ERR,
"Couldn't find a video stream");
590 m_codecCtx->skip_loop_filter = AVDISCARD_DEFAULT;
599 LOG(VB_GENERAL, LOG_ERR,
600 "ThumbFinder: Couldn't find codec for video stream");
607 LOG(VB_GENERAL, LOG_ERR,
608 "ThumbFinder: Couldn't open codec for video stream");
625 frm_dir_map_t::const_iterator it =
m_deleteMap.constFind(frameNumber);
629 int start = it.key();
634 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
640 if (start <= frameNumber + diff)
645 return frameNumber + diff;
664 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder::SeekToFrame: seek failed") ;
685 frm_dir_map_t::const_iterator it;
688 if (it.key() > (uint64_t)currentFrame)
700 inc = (int) (inc * ceil(
m_fps));
702 int64_t newFrame = currentFrame + inc -
m_offset;
703 if (newFrame == currentFrame + 1)
721 frm_dir_map_t::const_iterator it;
725 if (it.key() >= (uint64_t)currentFrame)
737 inc = (int) (-inc * ceil(
m_fps));
739 int64_t newFrame = currentFrame + inc -
m_offset;
749 memset(&orig, 0,
sizeof(
AVFrame));
750 memset(&retbuf, 0,
sizeof(
AVFrame));
752 AVPacket *pkt = av_packet_alloc();
755 LOG(VB_GENERAL, LOG_ERR,
"packet allocation failed");
759 bool frameFinished =
false;
760 bool gotKeyFrame =
false;
762 while (av_read_frame(
m_inputFC, pkt) >= 0 && !frameFinished)
766 int keyFrame = pkt->flags & AV_PKT_FLAG_KEY;
768 if (
m_startPTS == -1 && pkt->dts != AV_NOPTS_VALUE)
777 if (!gotKeyFrame && needKeyFrame)
779 av_packet_unref(pkt);
787 frameFinished =
false;
790 frameFinished =
true;
791 if (ret == 0 || ret == AVERROR(EAGAIN))
793 if (requiredPTS != -1 && pkt->dts != AV_NOPTS_VALUE && pkt->dts < requiredPTS)
794 frameFinished =
false;
799 av_packet_unref(pkt);
801 av_packet_free(&pkt);
805 av_image_fill_arrays(retbuf.data, retbuf.linesize,
m_outputbuf,
813 QImage::Format_RGB32);
816 if (!img.save(ffile.constData(),
"JPEG"))
851 auto *menuPopup =
new MythDialogBox(tr(
"Menu"), popupStack,
"actionmenu");
853 if (menuPopup->Create())
856 menuPopup->SetReturnEvent(
this,
"action");
868 auto *pixmap =
new QPixmap(size.width(), size.height());
871 QBrush brush(Qt::green);
875 p.fillRect(0, 0, size.width(), size.height(), brush);
877 frm_dir_map_t::const_iterator it;
879 brush.setColor(Qt::red);
883 double startdelta = size.width();
890 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
894 double enddelta = size.width();
898 int start = (int) (size.width() / startdelta);
899 int end = (int) (size.width() / enddelta);
900 p.fillRect(start - 1, 0, end - start, size.height(), brush);
905 brush.setColor(Qt::yellow);
907 p.fillRect(pos, 0, 3, size.height(), brush);
923 frm_dir_map_t::const_iterator it;
929 int start = it.key();
934 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
939 cutLen += end - start;
#define ENO
This can be appended to the LOG args with "+".
bool getThumbImages(void)
static constexpr int8_t PRE_SEEK_AMOUNT
virtual bool NextPrevWidgetFocus(bool up_or_down)
void updateCurrentPos(void)
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
static void DeinterlaceAVFrame(AVFrame *Frame)
Deinterlace an AVFrame.
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Screen in which all other widgets are contained and rendered.
ArchiveItem * m_archiveItem
MythPainter * GetPainter()
QString getTempDirectory(bool showError)
int calcFinalDuration(void)
MythUIType * GetFocusWidget(void) const
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
void changeSeekAmount(bool up)
MythUIButton * m_frameButton
bool Create(void) override
MythUIButtonList * m_imageGrid
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
bool SetFocusWidget(MythUIType *widget=nullptr)
bool getFileDetails(ArchiveItem *a)
Basic menu dialog, message and a list of options.
frm_dir_map_t m_deleteMap
bool getFrameImage(bool needKeyFrame=true, int64_t requiredPTS=-1)
QString GetShareDir(void)
MythUIButton * m_saveButton
void BuildFocusList(void)
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
int DecrRef(void) override
Decrements reference count and deletes on 0.
void FreeCodecContext(const AVStream *Stream)
bool initAVCodec(const QString &inFile)
MythUIImage * m_positionImage
void ShowMenu(void) override
ThumbFinder(MythScreenStack *parent, ArchiveItem *archiveItem, const QString &menuTheme)
int checkFramePosition(int frameNumber)
MythUIButton * m_cancelButton
ProgramInfo * getProgramInfoForFile(const QString &inFile)
static QString createThumbDir(void)
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
QString frameToTime(int64_t frame, bool addFrame=false) const
QList< ThumbImage * > m_thumbList
QList< ThumbImage * > thumbList
Holds information on recordings and videos.
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
void gridItemChanged(MythUIButtonListItem *item)
bool seekToFrame(int frame, bool checkPos=true)
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
bool Open(const QString &filename)
ArchiveRemoteAVFormatContext m_inputFC
virtual void SetText(const QString &text)
MythUIImage * m_frameImage
MythMainWindow * GetMythMainWindow(void)
static const std::array< const SeekAmount, 9 > kSeekAmounts
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
MythScreenStack * GetStack(const QString &Stackname)
void Assign(const QImage &img)
int Copy(AVFrame *To, const MythVideoFrame *From, unsigned char *Buffer, AVPixelFormat Fmt=AV_PIX_FMT_YUV420P)
Initialise AVFrame and copy contents of VideoFrame frame into it, performing any required conversion.
MythUIText * m_currentPosText
void updatePositionBar(int64_t frame)
unsigned char * m_outputbuf
MythUIText * m_seekAmountText
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
static int getChapterCount(const QString &menuTheme)
AVCodecContext * m_codecCtx