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();
353 if( chmod(qPrintable(thumbDir), 0777) != 0 )
354 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: Failed to change permissions"
355 " on thumb directory: " +
ENO);
359 for (
int x = 1; dir.exists(); x++)
361 path = thumbDir + QString(
"/%1").arg(x);
366 if( chmod(qPrintable(path), 0777) != 0 )
367 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: Failed to change permissions on "
368 "thumb directory: %1" +
ENO);
383 QString imageFile = thumb->
filename;
384 QFile dst(imageFile);
388 item->
SetImage(imageFile,
"",
true);
404 int sec = (int) (frame /
m_fps);
405 frame = frame - (int) (sec *
m_fps);
409 str += QString(
".%1").arg(frame,10,2,QChar(
'0'));
417 LOG(VB_GENERAL, LOG_ERR,
418 QString(
"ThumbFinder:: Failed to get file details for %1")
460 thumb->
frame = (int64_t) 0;
472 QCoreApplication::processEvents();
488 int chapter = chapterLen * (x - 1);
489 int hour = chapter / 3600;
490 int min = (chapter % 3600) / 60;
491 int sec = chapter % 60;
492 QString time = QString::asprintf(
"%02d:%02d:%02d", hour, min, sec);
494 auto frame = (int64_t) (chapter * ceil(
m_fps));
499 thumb->
frame = frame;
507 QCoreApplication::processEvents();
509 QCoreApplication::processEvents();
511 QCoreApplication::processEvents();
529 LOG(VB_JOBQUEUE, LOG_INFO, QString(
"ThumbFinder: Opening '%1'")
534 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder, Couldn't open input file" +
ENO);
539 int ret = avformat_find_stream_info(
m_inputFC,
nullptr);
542 LOG(VB_GENERAL, LOG_ERR,
543 QString(
"Couldn't get stream info, error #%1").arg(ret));
547 av_dump_format(
m_inputFC, 0, qPrintable(inFile), 0);
555 if (
m_inputFC->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
558 if (
m_inputFC->streams[i]->start_time != (
int) AV_NOPTS_VALUE)
562 LOG(VB_GENERAL, LOG_ERR,
563 "ThumbFinder: Failed to get start time");
570 if (st->r_frame_rate.den && st->r_frame_rate.num)
571 m_fps = av_q2d(st->r_frame_rate);
573 m_fps = 1/av_q2d(st->time_base);
580 LOG(VB_GENERAL, LOG_ERR,
"Couldn't find a video stream");
592 m_codecCtx->skip_loop_filter = AVDISCARD_DEFAULT;
601 LOG(VB_GENERAL, LOG_ERR,
602 "ThumbFinder: Couldn't find codec for video stream");
609 LOG(VB_GENERAL, LOG_ERR,
610 "ThumbFinder: Couldn't open codec for video stream");
627 frm_dir_map_t::const_iterator it =
m_deleteMap.constFind(frameNumber);
631 int start = it.key();
636 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
642 if (start <= frameNumber + diff)
647 return frameNumber + diff;
666 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder::SeekToFrame: seek failed") ;
687 frm_dir_map_t::const_iterator it;
690 if (it.key() > (uint64_t)currentFrame)
702 inc = (int) (inc * ceil(
m_fps));
704 int64_t newFrame = currentFrame + inc -
m_offset;
705 if (newFrame == currentFrame + 1)
723 frm_dir_map_t::const_iterator it;
727 if (it.key() >= (uint64_t)currentFrame)
739 inc = (int) (-inc * ceil(
m_fps));
741 int64_t newFrame = currentFrame + inc -
m_offset;
751 memset(&orig, 0,
sizeof(
AVFrame));
752 memset(&retbuf, 0,
sizeof(
AVFrame));
754 AVPacket *pkt = av_packet_alloc();
757 LOG(VB_GENERAL, LOG_ERR,
"packet allocation failed");
761 bool frameFinished =
false;
762 bool gotKeyFrame =
false;
764 while (av_read_frame(
m_inputFC, pkt) >= 0 && !frameFinished)
768 int keyFrame = pkt->flags & AV_PKT_FLAG_KEY;
770 if (
m_startPTS == -1 && pkt->dts != AV_NOPTS_VALUE)
779 if (!gotKeyFrame && needKeyFrame)
781 av_packet_unref(pkt);
789 frameFinished =
false;
792 frameFinished =
true;
793 if (ret == 0 || ret == AVERROR(EAGAIN))
795 if (requiredPTS != -1 && pkt->dts != AV_NOPTS_VALUE && pkt->dts < requiredPTS)
796 frameFinished =
false;
801 av_packet_unref(pkt);
803 av_packet_free(&pkt);
807 av_image_fill_arrays(retbuf.data, retbuf.linesize,
m_outputbuf,
815 QImage::Format_RGB32);
818 if (!img.save(ffile.constData(),
"JPEG"))
853 auto *menuPopup =
new MythDialogBox(tr(
"Menu"), popupStack,
"actionmenu");
855 if (menuPopup->Create())
858 menuPopup->SetReturnEvent(
this,
"action");
870 auto *pixmap =
new QPixmap(size.width(), size.height());
873 QBrush brush(Qt::green);
877 p.fillRect(0, 0, size.width(), size.height(), brush);
879 frm_dir_map_t::const_iterator it;
881 brush.setColor(Qt::red);
885 double startdelta = size.width();
892 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
896 double enddelta = size.width();
900 int start = (int) (size.width() / startdelta);
901 int end = (int) (size.width() / enddelta);
902 p.fillRect(start - 1, 0, end - start, size.height(), brush);
907 brush.setColor(Qt::yellow);
909 p.fillRect(pos, 0, 3, size.height(), brush);
925 frm_dir_map_t::const_iterator it;
931 int start = it.key();
936 LOG(VB_GENERAL, LOG_ERR,
"ThumbFinder: found a start cut but no cut end");
941 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