36#include <QApplication>
38#include <QDomDocument>
43#include <mythconfig.h>
60 #include <libavutil/imgutils.h>
64#define INT64_C(v) (v ## LL)
87 const QString &menuTheme)
89 m_archiveItem(archiveItem),
90 m_thumbCount(getChapterCount(menuTheme)),
91 m_thumbDir(createThumbDir())
136 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'mythburn'");
165 for (
int i = 0; i < actions.size() && !handled; i++)
167 const QString&
action = actions[i];
200 else if (
action ==
"DOWN")
204 else if (
action ==
"LEFT")
208 else if (
action ==
"RIGHT")
212 else if (
action ==
"SELECT")
236 menuTheme +
"/theme.xml";
237 QDomDocument doc(
"mydocument");
240 if (!
file.open(QIODevice::ReadOnly))
242 LOG(VB_GENERAL, LOG_ERR,
"Failed to open theme file: " +
filename);
245 if (!doc.setContent(&
file))
248 LOG(VB_GENERAL, LOG_ERR,
"Failed to parse theme file: " +
filename);
253 QDomNodeList chapterNodeList = doc.elementsByTagName(
"chapter");
255 return chapterNodeList.count();
268 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder::loadCutList: Got an empty delete map");
273 frm_dir_map_t::const_iterator it =
m_deleteMap.constBegin();
295 for (
const auto *item : std::as_const(
m_thumbList))
356 if( chmod(qPrintable(thumbDir), 0777) != 0 )
357 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: Failed to change permissions"
358 " on thumb directory: " +
ENO);
362 for (
int x = 1; dir.exists(); x++)
364 path = thumbDir + QString(
"/%1").arg(x);
369 if( chmod(qPrintable(path), 0777) != 0 )
370 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: Failed to change permissions on "
371 "thumb directory: %1" +
ENO);
386 QString imageFile = thumb->
filename;
387 QFile dst(imageFile);
391 item->
SetImage(imageFile,
"",
true);
407 int sec = (int) (frame /
m_fps);
408 frame = frame - (int) (sec *
m_fps);
412 str += QString(
".%1").arg(frame,10,2,QChar(
'0'));
420 LOG(VB_GENERAL, LOG_ERR,
421 QString(
"ThumbFinder:: Failed to get file details for %1")
463 thumb->
frame = (int64_t) 0;
477 QCoreApplication::processEvents();
493 int chapter = chapterLen * (x - 1);
494 int hour = chapter / 3600;
495 int min = (chapter % 3600) / 60;
496 int sec = chapter % 60;
497 QString time = QString::asprintf(
"%02d:%02d:%02d", hour, min, sec);
499 auto frame = (int64_t) (chapter * ceil(
m_fps));
504 thumb->
frame = frame;
514 QCoreApplication::processEvents();
516 QCoreApplication::processEvents();
518 QCoreApplication::processEvents();
536 LOG(VB_JOBQUEUE, LOG_INFO, QString(
"ThumbFinder: Opening '%1'")
541 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder, Couldn't open input file" +
ENO);
546 int ret = avformat_find_stream_info(
m_inputFC,
nullptr);
549 LOG(VB_GENERAL, LOG_ERR,
550 QString(
"Couldn't get stream info, error #%1").arg(ret));
554 av_dump_format(
m_inputFC, 0, qPrintable(inFile), 0);
562 if (
m_inputFC->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
565 if (
m_inputFC->streams[i]->start_time != (
int) AV_NOPTS_VALUE)
569 LOG(VB_GENERAL, LOG_ERR,
570 "ThumbFinder: Failed to get start time");
577 if (st->r_frame_rate.den && st->r_frame_rate.num)
578 m_fps = av_q2d(st->r_frame_rate);
580 m_fps = 1/av_q2d(st->time_base);
587 LOG(VB_GENERAL, LOG_ERR,
"Couldn't find a video stream");
599 m_codecCtx->skip_loop_filter = AVDISCARD_DEFAULT;
608 LOG(VB_GENERAL, LOG_ERR,
609 "ThumbFinder: Couldn't find codec for video stream");
616 LOG(VB_GENERAL, LOG_ERR,
617 "ThumbFinder: Couldn't open codec for video stream");
634 frm_dir_map_t::const_iterator it =
m_deleteMap.constFind(frameNumber);
638 int start = it.key();
643 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
649 if (start <= frameNumber + diff)
654 return frameNumber + diff;
672 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder::SeekToFrame: seek failed") ;
693 frm_dir_map_t::const_iterator it;
696 if (it.key() > (uint64_t)currentFrame)
709 inc = (int) (inc * ceil(
m_fps));
712 int64_t newFrame = currentFrame + inc -
m_offset;
713 if (newFrame == currentFrame + 1)
731 frm_dir_map_t::const_iterator it;
735 if (it.key() >= (uint64_t)currentFrame)
748 inc = (int) (-inc * ceil(
m_fps));
751 int64_t newFrame = currentFrame + inc -
m_offset;
761 memset(&orig, 0,
sizeof(
AVFrame));
762 memset(&retbuf, 0,
sizeof(
AVFrame));
764 AVPacket *pkt = av_packet_alloc();
767 LOG(VB_GENERAL, LOG_ERR,
"packet allocation failed");
771 bool frameFinished =
false;
772 bool gotKeyFrame =
false;
774 while (av_read_frame(
m_inputFC, pkt) >= 0 && !frameFinished)
778 int keyFrame = pkt->flags & AV_PKT_FLAG_KEY;
780 if (
m_startPTS == -1 && pkt->dts != AV_NOPTS_VALUE)
789 if (!gotKeyFrame && needKeyFrame)
791 av_packet_unref(pkt);
799 frameFinished =
false;
802 frameFinished =
true;
803 if (ret == 0 || ret == AVERROR(EAGAIN))
805 if (requiredPTS != -1 && pkt->dts != AV_NOPTS_VALUE && pkt->dts < requiredPTS)
806 frameFinished =
false;
811 av_packet_unref(pkt);
813 av_packet_free(&pkt);
817 av_image_fill_arrays(retbuf.data, retbuf.linesize,
m_outputbuf,
825 QImage::Format_RGB32);
828 if (!img.save(ffile.constData(),
"JPEG"))
863 auto *menuPopup =
new MythDialogBox(tr(
"Menu"), popupStack,
"actionmenu");
865 if (menuPopup->Create())
868 menuPopup->SetReturnEvent(
this,
"action");
880 auto *pixmap =
new QPixmap(size.width(), size.height());
883 QBrush brush(Qt::green);
887 p.fillRect(0, 0, size.width(), size.height(), brush);
889 frm_dir_map_t::const_iterator it;
891 brush.setColor(Qt::red);
895 double startdelta = size.width();
902 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
906 double enddelta = size.width();
910 int start = (int) (size.width() / startdelta);
911 int end = (int) (size.width() / enddelta);
912 p.fillRect(start - 1, 0, end - start, size.height(), brush);
917 brush.setColor(Qt::yellow);
919 p.fillRect(pos, 0, 3, size.height(), brush);
935 frm_dir_map_t::const_iterator it;
941 int start = it.key();
946 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
951 cutLen += end - start;
bool getFileDetails(ArchiveItem *a)
ProgramInfo * getProgramInfoForFile(const QString &inFile)
QString getTempDirectory(bool showError)
bool Open(const QString &filename)
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.
static void DeinterlaceAVFrame(AVFrame *Frame)
Deinterlace an AVFrame.
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
void FreeCodecContext(const AVStream *Stream)
Basic menu dialog, message and a list of options.
void Assign(const QImage &img)
int DecrRef(void) override
Decrements reference count and deletes on 0.
MythPainter * GetPainter()
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Screen in which all other widgets are contained and rendered.
virtual bool NextPrevWidgetFocus(bool up_or_down)
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool SetFocusWidget(MythUIType *widget=nullptr)
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
virtual void SetText(const QString &text)
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Holds information on recordings and videos.
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
bool seekToFrame(int frame, bool checkPos=true)
void ShowMenu(void) override
unsigned char * m_outputbuf
QString frameToTime(int64_t frame, bool addFrame=false) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
QList< ThumbImage * > m_thumbList
bool initAVCodec(const QString &inFile)
ArchiveRemoteAVFormatContext m_inputFC
int checkFramePosition(int frameNumber)
MythUIButton * m_cancelButton
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
bool getFrameImage(bool needKeyFrame=true, int64_t requiredPTS=-1)
ArchiveItem * m_archiveItem
MythUIButton * m_saveButton
bool Create(void) override
frm_dir_map_t m_deleteMap
static int getChapterCount(const QString &menuTheme)
void updateCurrentPos(void)
MythUIImage * m_positionImage
void changeSeekAmount(bool up)
MythUIButton * m_frameButton
MythUIButtonList * m_imageGrid
void gridItemChanged(MythUIButtonListItem *item)
int calcFinalDuration(void)
void updatePositionBar(int64_t frame)
ThumbFinder(MythScreenStack *parent, ArchiveItem *archiveItem, const QString &menuTheme)
bool getThumbImages(void)
static QString createThumbDir(void)
MythUIText * m_seekAmountText
AVCodecContext * m_codecCtx
MythUIImage * m_frameImage
MythUIText * m_currentPosText
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
QString GetShareDir(void)
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MythMainWindow * GetMythMainWindow(void)
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
QList< ThumbImage * > thumbList
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
static constexpr int8_t PRE_SEEK_AMOUNT
static const std::array< const SeekAmount, 9 > kSeekAmounts