Ticket #6322: gridedit.trunk.code.5.patch
File gridedit.trunk.code.5.patch, 104.3 KB (added by , 15 years ago) |
---|
-
mythtv/libs/libmyth/mythdialogs.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmyth/mythdialogs.cpp myth.20155.0309b/mythtv/libs/libmyth/mythdialogs.cpp
1327 1327 rect_to_update = this->geometry(); 1328 1328 } 1329 1329 1330 redrawRect = redrawRect.unite(r );1330 redrawRect = redrawRect.unite(rect_to_update); 1331 1331 1332 1332 update(redrawRect); 1333 1333 } … … 1652 1652 return GetUIType<UIBlackHoleType>(this, name); 1653 1653 } 1654 1654 1655 UIGridEditImageType* MythThemedDialog::getUIGridEditImageType(const QString &name) 1656 { 1657 return GetUIType<UIGridEditImageType>(this, name); 1658 } 1659 1660 UIGridEditSliderType* MythThemedDialog::getUIGridEditSliderType(const QString &name) 1661 { 1662 return GetUIType<UIGridEditSliderType>(this, name); 1663 } 1664 1655 1665 UIImageType* MythThemedDialog::getUIImageType(const QString &name) 1656 1666 { 1657 1667 return GetUIType<UIImageType>(this, name); -
mythtv/libs/libmyth/mythdialogs.h
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmyth/mythdialogs.h myth.20155.0309b/mythtv/libs/libmyth/mythdialogs.h
26 26 class UICheckBoxType; 27 27 class UISelectorType; 28 28 class UIBlackHoleType; 29 class UIGridEditImageType; 30 class UIGridEditSliderType; 29 31 class UIImageType; 30 32 class UIImageGridType; 31 33 class UIStatusBarType; … … 373 375 UICheckBoxType *getUICheckBoxType(const QString &name); 374 376 UISelectorType *getUISelectorType(const QString &name); 375 377 UIBlackHoleType *getUIBlackHoleType(const QString &name); 378 UIGridEditImageType *getUIGridEditImageType(const QString &name); 379 UIGridEditSliderType *getUIGridEditSliderType(const QString &name); 376 380 UIImageGridType *getUIImageGridType(const QString &name); 377 381 UIImageType *getUIImageType(const QString &name); 378 382 UIStatusBarType *getUIStatusBarType(const QString &name); -
mythtv/libs/libmyth/uitypes.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmyth/uitypes.cpp myth.20155.0309b/mythtv/libs/libmyth/uitypes.cpp
4683 4683 4684 4684 // ******************************************************************** 4685 4685 4686 UIGridEditImageType::UIGridEditImageType(const QString &name) 4687 : UIType(name) 4688 { 4689 cutStatus = 0; 4690 highlightFrame = false; // Used to highlight frame #0 4691 framenumber = -1; 4692 } 4693 4694 void UIGridEditImageType::calculateScreenArea() 4695 { 4696 QRect r = area; 4697 r.translate(m_parent->GetAreaRect().left(), 4698 m_parent->GetAreaRect().top()); 4699 screen_area = r; 4700 4701 inner_border.setLeft(screen_area.left()+1); 4702 inner_border.setRight(screen_area.right()-1); 4703 inner_border.setTop(screen_area.top()+1); 4704 inner_border.setBottom(screen_area.bottom()-1); 4705 4706 outer_border = screen_area; 4707 } 4708 4709 void UIGridEditImageType::Draw(QPainter *p, int drawlayer, int context) 4710 { 4711 if (pmap.isNull()) 4712 { 4713 QColor drawcolor = QColor( 0, 0, 0); 4714 p->setBrush(QBrush(Qt::SolidPattern)); 4715 p->setPen(QPen(drawcolor, 2)); 4716 p->drawRect(screen_area); 4717 } 4718 else 4719 { 4720 p->drawPixmap(screen_area, pmap); 4721 4722 p->setBrush(QBrush(Qt::NoBrush)); 4723 // Draw the frame outline 4724 // This may be covered by the cut indicator 4725 // Or the highlight 4726 4727 p->setPen(QPen(colorSet[0], 3)); 4728 p->drawRect(outer_border); 4729 4730 if (cutStatus > 0) 4731 { 4732 p->setPen(QPen(colorSet[cutStatus], 3)); 4733 p->drawRect(inner_border); 4734 p->drawLine(inner_border.topLeft(), inner_border.bottomRight()); 4735 p->drawLine(inner_border.bottomLeft(), inner_border.topRight()); 4736 } 4737 if (highlightFrame) 4738 { 4739 // Overlay the image frame with the standard frame color 4740 // This is used to highlight small frame #0 4741 p->setPen(QPen(highlightColor, 3)); 4742 p->drawRect(outer_border); 4743 } 4744 } 4745 } 4746 4747 void UIGridEditImageType::setPixmap(QPixmap *new_pmap, long long frame, int new_cutStatus) 4748 { 4749 // We can get a null new_pmap at the start or end of the video 4750 if (! new_pmap) 4751 { 4752 clearPixmap(); 4753 return; 4754 } 4755 4756 if (frame == framenumber) 4757 { 4758 // No change in pixmap (?) 4759 setCutStatus(new_cutStatus); 4760 return; 4761 } 4762 4763 pmap = *new_pmap; 4764 framenumber = frame; 4765 4766 if (new_cutStatus >= 0 && new_cutStatus <= 3) 4767 cutStatus = new_cutStatus; 4768 else 4769 cutStatus = 0; 4770 4771 refresh(); 4772 } 4773 4774 void UIGridEditImageType::clearPixmap(bool dorefresh) 4775 { 4776 if (! pmap.isNull()) 4777 { 4778 pmap = QPixmap(); 4779 4780 cutStatus = 0; 4781 framenumber = -1; 4782 if (dorefresh) 4783 refresh(); 4784 } 4785 } 4786 4787 void UIGridEditImageType::setCutStatus(int new_cutStatus) 4788 { 4789 if (new_cutStatus == cutStatus) 4790 return; 4791 4792 if (new_cutStatus >= 0 && new_cutStatus <= 3) 4793 cutStatus = new_cutStatus; 4794 else 4795 cutStatus = 0; 4796 4797 refresh(); 4798 } 4799 4800 // ******************************************************************** 4801 4802 UIGridEditSliderType::UIGridEditSliderType(const QString &name) 4803 : UIType(name) 4804 { 4805 m_drawMap = NULL; 4806 m_position=0; 4807 } 4808 4809 void UIGridEditSliderType::calculateScreenArea() 4810 { 4811 QRect r = area; 4812 r.translate(m_parent->GetAreaRect().left(), 4813 m_parent->GetAreaRect().top()); 4814 screen_area = r; 4815 4816 if (m_drawMap) 4817 delete [] m_drawMap; 4818 4819 m_drawWidth = area.width(); 4820 m_drawMap = new unsigned char[m_drawWidth]; 4821 for (int i = 0; i < m_drawWidth; i++) 4822 m_drawMap[i] = 0; 4823 } 4824 4825 void UIGridEditSliderType::ClearAll() 4826 { 4827 for (int i = 0; i < m_drawWidth; i++) 4828 m_drawMap[i] = 0; 4829 refresh(); 4830 } 4831 4832 void UIGridEditSliderType::SetRange( 4833 long long fstart, long long fend, long long fcount) 4834 { 4835 if (fcount <= 0) 4836 { 4837 VERBOSE(VB_IMPORTANT, QString("Invalid frame count: %1") 4838 .arg(fcount)); 4839 return; 4840 } 4841 if (fstart < 0) 4842 { 4843 VERBOSE(VB_IMPORTANT, QString("Invalid starting frame: %1") 4844 .arg(fstart)); 4845 return; 4846 } 4847 if (fend < 0) 4848 { 4849 VERBOSE(VB_IMPORTANT, QString("Invalid ending frame: %1") 4850 .arg(fend)); 4851 return; 4852 } 4853 4854 if (fstart > fcount) fstart = fcount; 4855 if (fend > fcount) fend = fcount; 4856 4857 int start = (int)((1.0 * fstart * m_drawWidth) / fcount); 4858 int end = (int)((1.0 * fend * m_drawWidth) / fcount); 4859 4860 if (start < 0) 4861 start = 0; 4862 if (start >= m_drawWidth) 4863 start = m_drawWidth - 1; 4864 if (end < 0) 4865 end = 0; 4866 if (end >= m_drawWidth) 4867 end = m_drawWidth - 1; 4868 4869 if (end < start) 4870 { 4871 int tmp = start; 4872 start = end; 4873 end = tmp; 4874 } 4875 4876 for (int i = start; i < end; i++) 4877 if (m_drawMap[i] < 1) 4878 m_drawMap[i] = 1; 4879 4880 // Mark endpoints 4881 m_drawMap[start] = 2; 4882 m_drawMap[end] = 2; 4883 4884 VERBOSE(VB_GENERAL, QString("Range = %1 - %2 (%3 - %4)") 4885 .arg(start).arg(end) 4886 .arg(fstart).arg(fend)); 4887 refresh(); 4888 } 4889 4890 void UIGridEditSliderType::SetPosition( 4891 long long fposition, long long fcount) 4892 { 4893 if (fcount <= 0) 4894 { 4895 VERBOSE(VB_IMPORTANT, QString("Invalid frame count: %1") 4896 .arg(fcount)); 4897 return; 4898 } 4899 4900 if (fposition < 0) 4901 { 4902 VERBOSE(VB_IMPORTANT, QString("Invalid position frame: %1") 4903 .arg(fposition)); 4904 return; 4905 } 4906 4907 if (fposition > fcount) fposition = fcount; 4908 4909 int new_position = (int)(1.0 * fposition * m_drawWidth) / fcount; 4910 4911 if (new_position < 0) 4912 new_position = 0; 4913 if (new_position >= m_drawWidth) 4914 new_position = m_drawWidth - 1; 4915 4916 if (new_position != m_position) 4917 { 4918 m_position = new_position; 4919 refresh(); 4920 } 4921 } 4922 4923 void UIGridEditSliderType::Draw(QPainter *p, int drawlayer, int context) 4924 { 4925 // Draw Background 4926 p->setPen(QPen(colorSet[0], 2)); 4927 p->setBrush(colorSet[0]); 4928 p->drawRect(screen_area); 4929 4930 // Draw bars 4931 4932 // VERBOSE(VB_GENERAL, QString("Starting")); 4933 int i = 0; 4934 do { 4935 int start = 0; 4936 int end = 0; 4937 4938 while (i < m_drawWidth && m_drawMap[i] == 0) i++; 4939 if (i == m_drawWidth) break; 4940 start = i; 4941 4942 i++; 4943 4944 4945 while (i < m_drawWidth && m_drawMap[i] == 1) i++; 4946 end = i; 4947 if (end == m_drawWidth) end--; 4948 4949 // If the next map value is not a normal internal cutpoint 4950 // increment i so we handle it properly 4951 if (end+1 < m_drawWidth && m_drawMap[end+1] != 1) 4952 i++; 4953 4954 // start == starting point 4955 // end == endingpoint 4956 { 4957 QRect r = screen_area; 4958 r.setLeft(r.left() + start); 4959 r.setWidth(end - start); 4960 4961 // VERBOSE(VB_GENERAL, QString("Cut from (%1, %2) - (%3, %4)") 4962 // .arg(r.left()).arg(r.top()) 4963 // .arg(r.right()).arg(r.bottom())); 4964 4965 // VERBOSE(VB_GENERAL, QString("start = %1, m_position = %2, end = %3") 4966 // .arg(start) 4967 // .arg(m_position) 4968 // .arg(end)); 4969 4970 if (start <= m_position && m_position <= end) 4971 { 4972 p->setPen(QPen(colorSet[4], 2)); 4973 p->setBrush(colorSet[4]); 4974 } 4975 else 4976 { 4977 p->setPen(QPen(colorSet[1], 2)); 4978 p->setBrush(colorSet[1]); 4979 } 4980 p->drawRect(r); 4981 4982 p->setPen(QPen(colorSet[2], 2)); 4983 p->setBrush(colorSet[2]); 4984 if (m_drawMap[start] == 2) 4985 p->drawLine(r.topLeft(), r.bottomLeft()); 4986 if (m_drawMap[end] == 2) 4987 p->drawLine(r.topRight(), r.bottomRight()); 4988 4989 } 4990 } while (i < m_drawWidth); 4991 4992 // Draw Current Position Mark 4993 4994 QPoint ptop(screen_area.left() + m_position, screen_area.top()); 4995 QPoint pbot(screen_area.left() + m_position, screen_area.bottom()); 4996 4997 p->setPen(QPen(colorSet[3], 2)); 4998 p->setBrush(colorSet[3]); 4999 p->drawLine(ptop, pbot); 5000 } 5001 5002 // ******************************************************************** 5003 4686 5004 UIKeyType::UIKeyType(const QString &name) 4687 5005 : UIType(name) 4688 5006 { -
mythtv/libs/libmyth/uitypes.h
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmyth/uitypes.h myth.20155.0309b/mythtv/libs/libmyth/uitypes.h
1172 1172 QRect area; 1173 1173 }; 1174 1174 1175 class MPUBLIC UIGridEditImageType : public UIType 1176 { 1177 Q_OBJECT 1178 1179 public: 1180 1181 UIGridEditImageType(const QString &name); 1182 void calculateScreenArea(); 1183 void setArea(QRect an_area) { area = an_area; }; 1184 1185 void setOutlineColor(QColor c) { colorSet[0] = c; }; 1186 void setCutColor(QColor c) { colorSet[1] = c; }; 1187 void setCutPointColor(QColor c) 1188 { 1189 colorSet[2] = c; // Cut before 1190 colorSet[3] = c; // Cut after 1191 }; 1192 void setHighlightFrame(bool high) { highlightFrame = high; }; 1193 void setHighlightColor(QColor c) { highlightColor = c; }; 1194 1195 virtual void Draw(QPainter *, int, int); 1196 void setPixmap(QPixmap *new_pmap, long long frame, int new_cutStatus); 1197 1198 void clearPixmap(bool dorefresh=true); 1199 void setCutStatus(int new_cutStatus); 1200 1201 QRect getOuterBorder() { return outer_border; }; 1202 protected: 1203 1204 QRect area; 1205 QRect inner_border; 1206 QRect outer_border; 1207 QPixmap pmap; 1208 long long framenumber; // for consistency checking 1209 int cutStatus; 1210 QColor colorSet[4]; 1211 bool highlightFrame; 1212 QColor highlightColor; 1213 }; 1214 1215 class MPUBLIC UIGridEditSliderType : public UIType 1216 { 1217 Q_OBJECT 1218 1219 public: 1220 1221 UIGridEditSliderType(const QString &name); 1222 void calculateScreenArea(); 1223 void setArea(QRect an_area) { area = an_area; }; 1224 1225 void setFillColor(QColor c) { colorSet[0] = c; }; 1226 void setCutColor(QColor c) { colorSet[1] = c; }; 1227 void setCutPointColor(QColor c) { colorSet[2] = c; }; 1228 void setPositionColor(QColor c) { colorSet[3] = c; }; 1229 void setInCutColor(QColor c) { colorSet[4] = c; }; 1230 1231 void ClearAll(); 1232 void SetRange(long long fstart, long long fend, long long fcount); 1233 void SetPosition(long long fposition, long long fcount); 1234 1235 virtual void Draw(QPainter *, int, int); 1236 protected: 1237 1238 QRect area; 1239 unsigned char *m_drawMap; 1240 int m_drawWidth; 1241 int m_position; 1242 1243 QColor colorSet[5]; 1244 }; 1245 1246 1175 1247 class MPUBLIC UIKeyType : public UIType 1176 1248 { 1177 1249 Q_OBJECT -
mythtv/libs/libmyth/xmlparse.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmyth/xmlparse.cpp myth.20155.0309b/mythtv/libs/libmyth/xmlparse.cpp
1363 1363 { 1364 1364 parseBlackHole(container, info); 1365 1365 } 1366 else if (info.tagName() == "grideditimage") 1367 { 1368 parseGridEditImage(container, info); 1369 } 1370 else if (info.tagName() == "grideditslider") 1371 { 1372 parseGridEditSlider(container, info); 1373 } 1366 1374 else if (info.tagName() == "area") 1367 1375 { 1368 1376 area = parseRect(getFirstText(info)); … … 3126 3134 container->AddType(bh); 3127 3135 } 3128 3136 3137 3138 void XMLParse::parseGridEditImage(LayerSet *container, QDomElement &element) 3139 { 3140 QRect area; 3141 QColor outlineColor; 3142 QColor cutColor; 3143 QColor cutPointColor; 3144 QColor highlightColor; 3145 bool haveOutlineColor = false; 3146 bool haveCutColor = false; 3147 bool haveCutPointColor = false; 3148 bool haveHighlightColor = false; 3149 bool highlightFrame = false; 3150 3151 QString name = element.attribute("name", ""); 3152 if (name.isNull() || name.isEmpty()) 3153 { 3154 VERBOSE(VB_IMPORTANT, LOC_WARN + "GridEditImage needs a name"); 3155 return; 3156 } 3157 QString highlight = element.attribute("highlightframe", ""); 3158 if (highlight == "true") 3159 highlightFrame = true; 3160 3161 for (QDomNode child = element.firstChild(); !child.isNull(); 3162 child = child.nextSibling()) 3163 { 3164 QDomElement info = child.toElement(); 3165 if (!info.isNull()) 3166 { 3167 if (info.tagName() == "area") 3168 { 3169 area = parseRect(getFirstText(info)); 3170 normalizeRect(area); 3171 } 3172 else if (info.tagName() == "outlinecolor") 3173 { 3174 haveOutlineColor = true; 3175 outlineColor = getFirstText(info); 3176 } 3177 else if (info.tagName() == "cutcolor") 3178 { 3179 haveCutColor = true; 3180 cutColor = getFirstText(info); 3181 } 3182 else if (info.tagName() == "cutpointcolor") 3183 { 3184 haveCutPointColor = true; 3185 cutPointColor = getFirstText(info); 3186 } 3187 else if (info.tagName() == "highlightcolor") 3188 { 3189 haveHighlightColor = true; 3190 highlightColor = getFirstText(info); 3191 } 3192 else 3193 { 3194 VERBOSE(VB_IMPORTANT, LOC_WARN + 3195 QString("Unknown tag '%1' in grideditimage '%2'") 3196 .arg(info.tagName()).arg(name)); 3197 return; 3198 } 3199 } 3200 } 3201 3202 if (!haveOutlineColor) 3203 { 3204 VERBOSE(VB_IMPORTANT, LOC_WARN + 3205 QString("Missing tag 'outlinecolor' in grideditimage '%1'") 3206 .arg(name)); 3207 return; 3208 } 3209 3210 if (!haveCutColor) 3211 { 3212 VERBOSE(VB_IMPORTANT, LOC_WARN + 3213 QString("Missing tag 'cutcolor' in grideditimage '%1'") 3214 .arg(name)); 3215 return; 3216 } 3217 3218 if (!haveCutPointColor) 3219 { 3220 VERBOSE(VB_IMPORTANT, LOC_WARN + 3221 QString("Missing tag 'cutpointcolor' in grideditimage '%1'") 3222 .arg(name)); 3223 return; 3224 } 3225 3226 if (highlightFrame && !haveHighlightColor) 3227 { 3228 VERBOSE(VB_IMPORTANT, LOC_WARN + 3229 QString("highlightframe specified but missing tag 'hightlightcolor' in grideditimage '%1'") 3230 .arg(name)); 3231 return; 3232 } 3233 3234 3235 UIGridEditImageType *gei = new UIGridEditImageType(name); 3236 gei->SetScreen(wmult, hmult); 3237 gei->setArea(area); 3238 gei->setOutlineColor(outlineColor); 3239 gei->setCutColor(cutColor); 3240 gei->setCutPointColor(cutPointColor); 3241 gei->setHighlightColor(highlightColor); 3242 gei->setHighlightFrame(highlightFrame); 3243 gei->SetParent(container); 3244 gei->calculateScreenArea(); 3245 gei->clearPixmap(false); 3246 container->AddType(gei); 3247 } 3248 3249 void XMLParse::parseGridEditSlider(LayerSet *container, QDomElement &element) 3250 { 3251 QRect area; 3252 QColor fillColor; 3253 QColor cutColor; 3254 QColor inCutColor; 3255 QColor cutPointColor; 3256 QColor positionColor; 3257 bool haveFillColor = false; 3258 bool haveCutColor = false; 3259 bool haveInCutColor = false; 3260 bool haveCutPointColor = false; 3261 bool havePositionColor = false; 3262 3263 QString name = element.attribute("name", ""); 3264 if (name.isNull() || name.isEmpty()) 3265 { 3266 VERBOSE(VB_IMPORTANT, LOC_WARN + "GridEditSlider needs a name"); 3267 return; 3268 } 3269 3270 for (QDomNode child = element.firstChild(); !child.isNull(); 3271 child = child.nextSibling()) 3272 { 3273 QDomElement info = child.toElement(); 3274 if (!info.isNull()) 3275 { 3276 if (info.tagName() == "area") 3277 { 3278 area = parseRect(getFirstText(info)); 3279 normalizeRect(area); 3280 } 3281 else if (info.tagName() == "fillcolor") 3282 { 3283 haveFillColor = true; 3284 fillColor = getFirstText(info); 3285 } 3286 else if (info.tagName() == "cutcolor") 3287 { 3288 haveCutColor = true; 3289 cutColor = getFirstText(info); 3290 } 3291 else if (info.tagName() == "incutcolor") 3292 { 3293 haveInCutColor = true; 3294 inCutColor = getFirstText(info); 3295 } 3296 else if (info.tagName() == "cutpointcolor") 3297 { 3298 haveCutPointColor = true; 3299 cutPointColor = getFirstText(info); 3300 } 3301 else if (info.tagName() == "positioncolor") 3302 { 3303 havePositionColor = true; 3304 positionColor = getFirstText(info); 3305 } 3306 else 3307 { 3308 VERBOSE(VB_IMPORTANT, LOC_WARN + 3309 QString("Unknown tag '%1' in grideditslider '%2'") 3310 .arg(info.tagName()).arg(name)); 3311 return; 3312 } 3313 } 3314 } 3315 3316 if (!haveFillColor) 3317 { 3318 VERBOSE(VB_IMPORTANT, LOC_WARN + 3319 QString("Missing tag 'fillcolor' in grideditslider '%1'") 3320 .arg(name)); 3321 return; 3322 } 3323 3324 if (!haveCutColor) 3325 { 3326 VERBOSE(VB_IMPORTANT, LOC_WARN + 3327 QString("Missing tag 'cutcolor' in grideditslider '%1'") 3328 .arg(name)); 3329 return; 3330 } 3331 3332 if (!haveInCutColor) 3333 { 3334 VERBOSE(VB_IMPORTANT, LOC_WARN + 3335 QString("Missing tag 'incutcolor' in grideditslider '%1'") 3336 .arg(name)); 3337 return; 3338 } 3339 3340 if (!haveCutPointColor) 3341 { 3342 VERBOSE(VB_IMPORTANT, LOC_WARN + 3343 QString("Missing tag 'cutpointcolor' in grideditslider '%1'") 3344 .arg(name)); 3345 return; 3346 } 3347 3348 if (!havePositionColor) 3349 { 3350 VERBOSE(VB_IMPORTANT, LOC_WARN + 3351 QString("Missing tag 'positioncolor' in grideditslider '%1'") 3352 .arg(name)); 3353 return; 3354 } 3355 3356 UIGridEditSliderType *ges = new UIGridEditSliderType(name); 3357 ges->SetScreen(wmult, hmult); 3358 ges->setArea(area); 3359 ges->setFillColor(fillColor); 3360 ges->setCutColor(cutColor); 3361 ges->setInCutColor(inCutColor); 3362 ges->setCutPointColor(cutPointColor); 3363 ges->setPositionColor(positionColor); 3364 ges->SetParent(container); 3365 ges->calculateScreenArea(); 3366 container->AddType(ges); 3367 } 3368 3129 3369 void XMLParse::parseListBtnArea(LayerSet *container, QDomElement &element) 3130 3370 { 3131 3371 int context = -1; -
mythtv/libs/libmyth/xmlparse.h
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmyth/xmlparse.h myth.20155.0309b/mythtv/libs/libmyth/xmlparse.h
47 47 void parseCheckBox(LayerSet *, QDomElement &); 48 48 void parseSelector(LayerSet *, QDomElement &); 49 49 void parseBlackHole(LayerSet *, QDomElement &); 50 void parseGridEditImage(LayerSet *, QDomElement &); 51 void parseGridEditSlider(LayerSet *, QDomElement &); 50 52 void parseListBtnArea(LayerSet *, QDomElement &); 51 53 void parseListTreeArea(LayerSet *, QDomElement &); 52 54 void parseKeyboard(LayerSet *, QDomElement &); -
mythtv/libs/libmythtv/NuppelVideoPlayer.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp myth.20155.0309b/mythtv/libs/libmythtv/NuppelVideoPlayer.cpp
55 55 #include "mythverbose.h" 56 56 #include "myth_imgconvert.h" 57 57 58 #include "grideditcutpoints.h" 59 58 60 extern "C" { 59 61 #include "vbitext/vbi.h" 60 62 #include "vsync.h" … … 166 168 decoder_thread_alive(true), killplayer(false), 167 169 killvideo(false), livetv(false), 168 170 watchingrecording(false), editmode(false), 171 hideedits(false), 169 172 resetvideo(false), using_null_videoout(false), 170 173 no_audio_in(false), no_audio_out(false), 171 174 transcoding(false), … … 175 178 bookmarkseek(0), previewFromBookmark(false), 176 179 // Seek 177 180 fftime(0), seekamountpos(4), 178 seekamount(30), exactseeks(false), 181 allow_pagesize(false), half_page(0), 182 seekamount(30), seekamounttext("30 Frames"), 183 exactseeks(false), 179 184 // Playback misc. 180 185 videobuf_retries(0), framesPlayed(0), 181 186 totalFrames(0), totalLength(0), … … 225 230 yuv_need_copy(false), yuv_desired_size(0,0), 226 231 yuv_scaler(NULL), yuv_frame_scaled(NULL), 227 232 yuv_scaler_in_size(0,0), yuv_scaler_out_size(0,0), 233 // Grid Editing 234 grid_edit_image_scaler(NULL), grid_edit_image_small_scaler(NULL), 235 grid_edit_image_buffer_yuv(NULL), grid_edit_image_small_buffer_yuv(NULL), 236 grid_edit_image_buffer_rgb(NULL), grid_edit_image_small_buffer_rgb(NULL), 237 grid_edit_image_buffer_length(0), grid_edit_image_small_buffer_length(0), 238 grid_edit_image_in_size(-1, -1), 239 228 240 // Filters 229 241 videoFiltersForProgram(""), videoFiltersOverride(""), 230 242 postfilt_width(0), postfilt_height(0), … … 371 383 output_jmeter = NULL; 372 384 } 373 385 386 ClearScreenGrab(); 387 374 388 ShutdownYUVResize(); 375 389 } 376 390 … … 1605 1619 return retval; 1606 1620 } 1607 1621 1622 1623 bool NuppelVideoPlayer::GetScreenGrabsOfCurrentFrame(QImage &normal, QImage &small) 1624 { 1625 1626 unsigned char *data = NULL; 1627 VideoFrame *frame = NULL; 1628 AVPicture orig; 1629 AVPicture scaled; 1630 AVPicture scaled_small; 1631 bzero(&orig, sizeof(AVPicture)); 1632 bzero(&scaled, sizeof(AVPicture)); 1633 bzero(&scaled_small, sizeof(AVPicture)); 1634 1635 int vw, vh; 1636 if (!(frame = GetCurrentFrame(vw, vh))) 1637 { 1638 return false; 1639 } 1640 1641 if (!(data = frame->buf)) 1642 { 1643 ReleaseCurrentFrame(frame); 1644 return false; 1645 } 1646 1647 // Check to see if the screen dimensions have changed 1648 // Probably shouldn't happen in normal use. 1649 if (grid_edit_image_in_size != video_dim) 1650 SetupScreenGrab(); 1651 1652 avpicture_fill(&orig, data, PIX_FMT_YUV420P, 1653 video_dim.width(), video_dim.height()); 1654 1655 avpicture_deinterlace(&orig, &orig, PIX_FMT_YUV420P, 1656 video_dim.width(), video_dim.height()); 1657 1658 // Rescale to the normal size 1659 avpicture_fill(&scaled, grid_edit_image_buffer_yuv, PIX_FMT_YUV420P, 1660 grid_edit_image_size.width(), 1661 grid_edit_image_size.height()); 1662 1663 img_resample(grid_edit_image_scaler, &scaled, &orig); 1664 1665 // Don't need the current frame anymore so release it 1666 ReleaseCurrentFrame(frame); 1667 1668 // Rescale to the small size 1669 avpicture_fill(&scaled_small, grid_edit_image_small_buffer_yuv, PIX_FMT_YUV420P, 1670 grid_edit_image_small_size.width(), 1671 grid_edit_image_small_size.height()); 1672 1673 img_resample(grid_edit_image_small_scaler, &scaled_small, &scaled); 1674 1675 // Convert scaled and scaled_small from YUV to RGB 1676 1677 // scaled first 1678 uint w = grid_edit_image_size.width(); 1679 uint h = grid_edit_image_size.height(); 1680 unsigned char *yuv_buf = grid_edit_image_buffer_yuv; 1681 unsigned char *rgb_buf = grid_edit_image_buffer_rgb; 1682 yuv2argb_conv(rgb_buf, 1683 yuv_buf, yuv_buf + (w * h), yuv_buf + (w * h * 5 / 4), 1684 w, h, w * 4, w, w / 2, 0); 1685 1686 // scaled_small next 1687 w = grid_edit_image_small_size.width(); 1688 h = grid_edit_image_small_size.height(); 1689 yuv_buf = grid_edit_image_small_buffer_yuv; 1690 rgb_buf = grid_edit_image_small_buffer_rgb; 1691 yuv2argb_conv(rgb_buf, 1692 yuv_buf, yuv_buf + (w * h), yuv_buf + (w * h * 5 / 4), 1693 w, h, w * 4, w, w / 2, 0); 1694 1695 #ifdef MMX 1696 #define _RGBSWAP .rgbSwapped() 1697 #endif 1698 1699 normal = QImage(grid_edit_image_buffer_rgb, 1700 grid_edit_image_size.width(), grid_edit_image_size.height(), 1701 QImage::Format_RGB32)_RGBSWAP; 1702 1703 small = QImage(grid_edit_image_small_buffer_rgb, 1704 grid_edit_image_small_size.width(), grid_edit_image_small_size.height(), 1705 QImage::Format_RGB32)_RGBSWAP; 1706 1707 return true; 1708 } 1709 1710 void NuppelVideoPlayer::SetScreenGrabSizes(QSize normal, QSize small) 1711 { 1712 grid_edit_image_size = normal; 1713 grid_edit_image_small_size = small; 1714 1715 SetupScreenGrab(); 1716 VERBOSE(VB_GENERAL, QString("Main Image = (%1, %2) from (%3, %4)") 1717 .arg(grid_edit_image_size.width()) 1718 .arg(grid_edit_image_size.height()) 1719 .arg(normal.width()).arg(normal.height())); 1720 VERBOSE(VB_GENERAL, QString("Small Image = (%1, %2) from (%3, %4)") 1721 .arg(grid_edit_image_small_size.width()) 1722 .arg(grid_edit_image_small_size.height()) 1723 .arg(small.width()).arg(small.height())); 1724 1725 } 1726 1727 void NuppelVideoPlayer::ClearScreenGrab() 1728 { 1729 if (grid_edit_image_scaler) 1730 { 1731 img_resample_close(grid_edit_image_scaler); 1732 grid_edit_image_scaler = NULL; 1733 } 1734 1735 if (grid_edit_image_small_scaler) 1736 { 1737 img_resample_close(grid_edit_image_small_scaler); 1738 grid_edit_image_small_scaler=NULL; 1739 } 1740 1741 if (grid_edit_image_buffer_yuv) 1742 { 1743 delete grid_edit_image_buffer_yuv; 1744 grid_edit_image_buffer_yuv=NULL; 1745 } 1746 1747 if (grid_edit_image_small_buffer_yuv) 1748 { 1749 delete grid_edit_image_small_buffer_yuv; 1750 grid_edit_image_small_buffer_yuv=NULL; 1751 } 1752 1753 if (grid_edit_image_buffer_rgb) 1754 { 1755 delete grid_edit_image_buffer_rgb; 1756 grid_edit_image_buffer_rgb=NULL; 1757 } 1758 1759 if (grid_edit_image_small_buffer_rgb) 1760 { 1761 delete grid_edit_image_small_buffer_rgb; 1762 grid_edit_image_small_buffer_rgb=NULL; 1763 } 1764 } 1765 1766 void NuppelVideoPlayer::SetupScreenGrab() 1767 { 1768 ClearScreenGrab(); 1769 grid_edit_image_in_size = video_dim; 1770 1771 // Normalize the output sizes. 1772 // This is necessary to preserve the aspect ratio 1773 1774 QSize tmpsize = grid_edit_image_size; 1775 grid_edit_image_size = video_dim; 1776 grid_edit_image_size.scale(tmpsize, Qt::KeepAspectRatio); 1777 1778 tmpsize = grid_edit_image_small_size; 1779 grid_edit_image_small_size = video_dim; 1780 grid_edit_image_small_size.scale(tmpsize, Qt::KeepAspectRatio); 1781 1782 grid_edit_image_size = QSize(grid_edit_image_size.width() & ~0x7, 1783 grid_edit_image_size.height() & ~0x7); 1784 grid_edit_image_small_size = QSize(grid_edit_image_small_size.width() & ~0x7, 1785 grid_edit_image_small_size.height() & ~0x7); 1786 1787 // Do normal first 1788 uint sz = grid_edit_image_size.width() * grid_edit_image_size.height(); 1789 grid_edit_image_buffer_yuv = new unsigned char[(sz * 3 / 2) + 128]; 1790 grid_edit_image_buffer_rgb = new unsigned char[sz * 4 + 128]; 1791 1792 grid_edit_image_scaler = img_resample_init( 1793 grid_edit_image_size.width(), grid_edit_image_size.height(), 1794 grid_edit_image_in_size.width(), grid_edit_image_in_size.height()); 1795 1796 // Then small 1797 sz = grid_edit_image_small_size.width() * grid_edit_image_small_size.height(); 1798 grid_edit_image_small_buffer_yuv = new unsigned char[(sz * 3 / 2) + 128]; 1799 grid_edit_image_small_buffer_rgb = new unsigned char[sz * 4 + 128]; 1800 1801 // Resize from normal to small 1802 grid_edit_image_small_scaler = img_resample_init( 1803 grid_edit_image_small_size.width(), grid_edit_image_small_size.height(), 1804 grid_edit_image_size.width(), grid_edit_image_size.height()); 1805 } 1806 1608 1807 void NuppelVideoPlayer::ReleaseCurrentFrame(VideoFrame *frame) 1609 1808 { 1610 1809 if (frame) … … 4988 5187 4989 5188 dialogname = ""; 4990 5189 5190 osd->HideAllExcept("editmode"); 5191 4991 5192 QMap<QString, QString> infoMap; 4992 5193 player_ctx->LockPlayingInfo(__FILE__, __LINE__); 4993 5194 player_ctx->playingInfo->ToMap(infoMap); … … 5052 5253 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 5053 5254 } 5054 5255 5256 bool NuppelVideoPlayer::EditSeekToFrame(long long targetFrame) 5257 { 5258 bool tmpexactseeks = exactseeks; 5259 GetDecoder()->setExactSeeks(true); 5260 5261 // VERBOSE(VB_GENERAL, QString("Before current frame = %1, going to frame %2") 5262 // .arg(GetFramesPlayed()) 5263 // .arg(targetFrame)); 5264 5265 if (framesPlayed > targetFrame) 5266 { 5267 // seek back 5268 rewindtime = framesPlayed - targetFrame; 5269 while (rewindtime != 0) 5270 usleep(1000); 5271 } 5272 else 5273 { 5274 // seek forward 5275 fftime = targetFrame - framesPlayed; 5276 while (fftime != 0) 5277 usleep(1000); 5278 5279 } 5280 // VERBOSE(VB_GENERAL, QString("After current frame = %1") 5281 // .arg(GetFramesPlayed())); 5282 GetDecoder()->setExactSeeks(tmpexactseeks); 5283 return (targetFrame == framesPlayed); 5284 } 5285 5286 void NuppelVideoPlayer::EditHandleClearMap() 5287 { 5288 QMap<long long, int>::Iterator it; 5289 for (it = deleteMap.begin(); it != deleteMap.end(); ++it) 5290 osd->HideEditArrow(it.key(), *it); 5291 5292 deleteMap.clear(); 5293 UpdateEditSlider(); 5294 } 5295 5296 void NuppelVideoPlayer::EditHandleInvertMap() 5297 { 5298 QMap<long long, int>::Iterator it; 5299 for (it = deleteMap.begin(); it != deleteMap.end(); ++it) 5300 ReverseMark(it.key()); 5301 5302 UpdateEditSlider(); 5303 UpdateTimeDisplay(); 5304 } 5305 5306 void NuppelVideoPlayer::EditHandleLoadCommSkip() 5307 { 5308 if (hascommbreaktable) 5309 { 5310 commBreakMapLock.lock(); 5311 QMap<long long, int>::Iterator it; 5312 for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it) 5313 { 5314 if (!deleteMap.contains(it.key())) 5315 { 5316 if (*it == MARK_COMM_START) 5317 AddMark(it.key(), MARK_CUT_START); 5318 else 5319 AddMark(it.key(), MARK_CUT_END); 5320 } 5321 } 5322 commBreakMapLock.unlock(); 5323 UpdateEditSlider(); 5324 UpdateTimeDisplay(); 5325 } 5326 } 5327 5055 5328 bool NuppelVideoPlayer::DoKeypress(QKeyEvent *e) 5056 5329 { 5057 5330 bool handled = false; … … 5131 5404 UpdateTimeDisplay(); 5132 5405 } 5133 5406 else if (action == "CLEARMAP") 5134 { 5135 QMap<long long, int>::Iterator it; 5136 for (it = deleteMap.begin(); it != deleteMap.end(); ++it) 5137 osd->HideEditArrow(it.key(), *it); 5138 5139 deleteMap.clear(); 5140 UpdateEditSlider(); 5141 } 5407 EditHandleClearMap(); 5142 5408 else if (action == "INVERTMAP") 5143 { 5144 QMap<long long, int>::Iterator it; 5145 for (it = deleteMap.begin(); it != deleteMap.end(); ++it) 5146 ReverseMark(it.key()); 5147 5148 UpdateEditSlider(); 5149 UpdateTimeDisplay(); 5150 } 5409 EditHandleInvertMap(); 5151 5410 else if (action == "LOADCOMMSKIP") 5152 { 5153 if (hascommbreaktable) 5154 { 5155 commBreakMapLock.lock(); 5156 QMap<long long, int>::Iterator it; 5157 for (it = commBreakMap.begin(); it != commBreakMap.end(); ++it) 5158 { 5159 if (!deleteMap.contains(it.key())) 5160 { 5161 if (*it == MARK_COMM_START) 5162 AddMark(it.key(), MARK_CUT_START); 5163 else 5164 AddMark(it.key(), MARK_CUT_END); 5165 } 5166 } 5167 commBreakMapLock.unlock(); 5168 UpdateEditSlider(); 5169 UpdateTimeDisplay(); 5170 } 5171 } 5411 EditHandleLoadCommSkip(); 5172 5412 else if (action == "PREVCUT") 5173 5413 { 5174 5414 int old_seekamount = seekamount; … … 5214 5454 UpdateEditSlider(); 5215 5455 UpdateTimeDisplay(); 5216 5456 } 5217 else if (action == "ESCAPE" || action == "MENU" || 5218 action == "TOGGLEEDIT") 5457 else if (action == "TOGGLEEDIT" || action == "MENU") 5458 m_tv->ShowEditRecordingGrid(); 5459 else if (action == "ESCAPE") 5219 5460 { 5220 5461 DisableEdit(); 5221 5462 retval = false; … … 5228 5469 return retval; 5229 5470 } 5230 5471 5472 void NuppelVideoPlayer::ShowEditRecordingGrid(void) 5473 { 5474 // Completely hide the OSD 5475 osd->HideAll(); 5476 hideedits = true; 5477 5478 GridEditCutpoints::Run(this); 5479 5480 ClearScreenGrab(); 5481 5482 allow_pagesize = false; 5483 hideedits = false; 5484 5485 // Show OSD 5486 5487 QMap<QString, QString> infoMap; 5488 player_ctx->LockPlayingInfo(__FILE__, __LINE__); 5489 player_ctx->playingInfo->ToMap(infoMap); 5490 infoMap.detach(); 5491 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 5492 5493 osd->SetText("editmode", infoMap, -1); 5494 5495 UpdateEditSlider(); 5496 UpdateTimeDisplay(); 5497 if (seekamountpos == 3 || seekamountpos == 4) 5498 UpdateSeekAmount(true); 5499 else 5500 UpdateSeekAmountDisplay(); 5501 5502 QMap<long long, int>::Iterator it; 5503 for (it = deleteMap.begin(); it != deleteMap.end(); ++it) 5504 AddMark(it.key(), *it); 5505 } 5506 5231 5507 AspectOverrideMode NuppelVideoPlayer::GetAspectOverride(void) const 5232 5508 { 5233 5509 if (videoOutput) … … 5304 5580 5305 5581 void NuppelVideoPlayer::UpdateSeekAmount(bool up) 5306 5582 { 5307 if (seekamountpos > 0 && !up) 5308 seekamountpos--; 5309 if (seekamountpos < 9 && up) 5310 seekamountpos++; 5583 if (up) 5584 { 5585 if (seekamountpos < 11) 5586 seekamountpos++; 5587 if (allow_pagesize) 5588 { 5589 if (seekamountpos == 1) 5590 seekamountpos = 2; 5591 } 5592 else 5593 { 5594 if (seekamountpos == 3 || seekamountpos == 4) 5595 seekamountpos = 5; 5596 } 5597 } 5598 else 5599 { 5600 if (seekamountpos > 0) 5601 seekamountpos--; 5602 if (allow_pagesize) 5603 { 5604 if (seekamountpos == 1) 5605 seekamountpos =0; 5606 } 5607 else 5608 { 5609 if (seekamountpos == 3 || seekamountpos == 4) 5610 seekamountpos = 2; 5611 } 5612 } 5311 5613 5312 5614 QString text = ""; 5313 5615 5314 5616 switch (seekamountpos) 5315 5617 { 5316 case 0: text = QObject::tr("cut point"); seekamount = -2; break; 5317 case 1: text = QObject::tr("keyframe"); seekamount = -1; break; 5318 case 2: text = QObject::tr("1 frame"); seekamount = 1; break; 5319 case 3: text = QObject::tr("0.5 seconds"); seekamount = (int)roundf(video_frame_rate / 2); break; 5320 case 4: text = QObject::tr("%n second(s)", "", 1); seekamount = (int)roundf(video_frame_rate); break; 5321 case 5: text = QObject::tr("%n second(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 5); break; 5322 case 6: text = QObject::tr("%n second(s)", "", 20); seekamount = (int)roundf(video_frame_rate * 20); break; 5323 case 7: text = QObject::tr("%n minute(s)", "", 1); seekamount = (int)roundf(video_frame_rate * 60); break; 5324 case 8: text = QObject::tr("%n minute(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 300); break; 5325 case 9: text = QObject::tr("%n minute(s)", "", 10); seekamount = (int)roundf(video_frame_rate * 600); break; 5618 case 0: text = QObject::tr("cut point"); seekamount = -2; break; 5619 5620 // Only for non-edit grid 5621 case 1: text = QObject::tr("keyframe"); seekamount = -1; break; 5622 // Only for non-edit grid 5623 5624 case 2: text = QObject::tr("1 frame"); seekamount = 1; break; 5625 5626 // Case 3 & 4 are for the edit grid only 5627 case 3: text = QObject::tr("1/2 Page"); seekamount = half_page; break; 5628 case 4: text = QObject::tr("Full Page"); seekamount = 2*half_page; break; 5629 // Case 3 & 4 are for the edit grid only 5630 5631 case 5: text = QObject::tr("0.5 seconds"); seekamount = (int)roundf(video_frame_rate / 2); break; 5632 case 6: text = QObject::tr("%n second(s)", "", 1); seekamount = (int)roundf(video_frame_rate); break; 5633 case 7: text = QObject::tr("%n second(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 5); break; 5634 case 8: text = QObject::tr("%n second(s)", "", 20); seekamount = (int)roundf(video_frame_rate * 20); break; 5635 case 9: text = QObject::tr("%n minute(s)", "", 1); seekamount = (int)roundf(video_frame_rate * 60); break; 5636 case 10: text = QObject::tr("%n minute(s)", "", 5); seekamount = (int)roundf(video_frame_rate * 300); break; 5637 case 11: text = QObject::tr("%n minute(s)", "", 10); seekamount = (int)roundf(video_frame_rate * 600); break; 5326 5638 default: text = QObject::tr("error"); seekamount = (int)roundf(video_frame_rate); break; 5327 5639 } 5328 5640 5641 seekamounttext = text; 5642 UpdateSeekAmountDisplay(); 5643 } 5644 5645 void NuppelVideoPlayer::UpdateSeekAmountDisplay(void) 5646 { 5329 5647 QMap<QString, QString> infoMap; 5330 infoMap["seekamount"] = text; 5331 osd->SetText("editmode", infoMap, -1); 5648 infoMap["seekamount"] = seekamounttext; 5649 if (!hideedits) 5650 osd->SetText("editmode", infoMap, -1); 5332 5651 } 5333 5652 5334 5653 void NuppelVideoPlayer::UpdateTimeDisplay(void) … … 5358 5677 infoMap["timedisplay"] = timestr; 5359 5678 infoMap["framedisplay"] = framestr; 5360 5679 infoMap["cutindicator"] = cutmarker; 5361 osd->SetText("editmode", infoMap, -1); 5680 if (!hideedits) 5681 osd->SetText("editmode", infoMap, -1); 5362 5682 } 5363 5683 5364 void NuppelVideoPlayer::HandleSelect(bool allowSelectNear)5684 DeletePointInfo NuppelVideoPlayer::GetDeletePointInfo(long long frame, bool allowSelectNear) 5365 5685 { 5366 bool deletepoint = false; 5367 bool cut_after = false; 5368 int direction = 0; 5686 DeletePointInfo retval; 5369 5687 5370 5688 if(!deleteMap.isEmpty()) 5371 5689 { 5372 5690 QMap<long long, int>::ConstIterator iter = deleteMap.begin(); 5373 5691 5374 while((iter != deleteMap.end()) && (iter.key() < frame sPlayed))5692 while((iter != deleteMap.end()) && (iter.key() < frame)) 5375 5693 ++iter; 5376 5694 5377 5695 if (iter == deleteMap.end()) 5378 5696 { 5379 5697 --iter; 5380 cut_after = !(*iter);5698 retval.cut_after = !(*iter); 5381 5699 } 5382 else if((iter != deleteMap.begin()) && (iter.key() != frame sPlayed))5700 else if((iter != deleteMap.begin()) && (iter.key() != frame)) 5383 5701 { 5384 5702 long long value = iter.key(); 5385 if((framesPlayed - (--iter).key()) > (value - frame sPlayed))5703 if((framesPlayed - (--iter).key()) > (value - frame)) 5386 5704 { 5387 cut_after = !(*iter);5705 retval.cut_after = !(*iter); 5388 5706 ++iter; 5389 5707 } 5390 5708 else 5391 cut_after = !(*iter);5709 retval.cut_after = !(*iter); 5392 5710 } 5393 5711 5394 direction = (*iter);5395 deleteframe = iter.key();5712 retval.direction = (*iter); 5713 retval.deleteframe = iter.key(); 5396 5714 5397 if ((absLongLong( deleteframe - framesPlayed) <5715 if ((absLongLong(retval.deleteframe - frame) < 5398 5716 (int)ceil(20 * video_frame_rate)) && !allowSelectNear) 5399 5717 { 5400 deletepoint = true;5718 retval.deletepoint = true; 5401 5719 } 5402 5720 } 5721 return retval; 5722 } 5403 5723 5404 if (deletepoint) 5724 void NuppelVideoPlayer::HandleSelect(bool allowSelectNear) 5725 { 5726 DeletePointInfo dpi = GetDeletePointInfo(framesPlayed, allowSelectNear); 5727 deleteframe = dpi.deleteframe; 5728 5729 if (dpi.deletepoint) 5405 5730 { 5406 5731 QString message = QObject::tr("You are close to an existing cut point. " 5407 5732 "Would you like to:"); … … 5409 5734 QString option2 = QObject::tr("Move this cut point to the current " 5410 5735 "position"); 5411 5736 QString option3 = QObject::tr("Flip directions - delete to the "); 5412 if (d irection == 0)5737 if (dpi.direction == 0) 5413 5738 option3 += QObject::tr("right"); 5414 5739 else 5415 5740 option3 += QObject::tr("left"); … … 5439 5764 options += option1; 5440 5765 options += option2; 5441 5766 5442 osd->NewDialogBox(dialogname, message, options, -1, cut_after);5767 osd->NewDialogBox(dialogname, message, options, -1, dpi.cut_after); 5443 5768 } 5444 5769 } 5445 5770 … … 5490 5815 5491 5816 void NuppelVideoPlayer::UpdateEditSlider(void) 5492 5817 { 5493 osd->DoEditSlider(deleteMap, framesPlayed, totalFrames); 5818 if (!hideedits) 5819 osd->DoEditSlider(deleteMap, framesPlayed, totalFrames); 5494 5820 } 5495 5821 5496 5822 void NuppelVideoPlayer::AddMark(long long frames, int type) 5497 5823 { 5498 5824 deleteMap[frames] = type; 5499 osd->ShowEditArrow(frames, totalFrames, type); 5825 if (!hideedits) 5826 osd->ShowEditArrow(frames, totalFrames, type); 5500 5827 } 5501 5828 5502 5829 void NuppelVideoPlayer::DeleteMark(long long frames) 5503 5830 { 5504 osd->HideEditArrow(frames, deleteMap[frames]); 5831 if (!hideedits) 5832 osd->HideEditArrow(frames, deleteMap[frames]); 5505 5833 deleteMap.remove(frames); 5506 5834 } 5507 5835 5508 5836 void NuppelVideoPlayer::ReverseMark(long long frames) 5509 5837 { 5510 osd->HideEditArrow(frames, deleteMap[frames]); 5838 if (!hideedits) 5839 osd->HideEditArrow(frames, deleteMap[frames]); 5511 5840 5512 5841 if (deleteMap[frames] == MARK_CUT_END) 5513 5842 deleteMap[frames] = MARK_CUT_START; 5514 5843 else 5515 5844 deleteMap[frames] = MARK_CUT_END; 5516 5845 5517 osd->ShowEditArrow(frames, totalFrames, deleteMap[frames]); 5846 if (!hideedits) 5847 osd->ShowEditArrow(frames, totalFrames, deleteMap[frames]); 5848 } 5849 5850 long long NuppelVideoPlayer::CalcCutPointSeek(long long baseframe, bool right) 5851 { 5852 QMap<long long, int>::Iterator i = deleteMap.begin(); 5853 long long framenum = -1; 5854 long long seekcount = 0; 5855 if (right) 5856 { 5857 for (; i != deleteMap.end(); ++i) 5858 { 5859 if (i.key() > baseframe) 5860 { 5861 framenum = i.key(); 5862 break; 5863 } 5864 } 5865 if (framenum == -1) 5866 framenum = totalFrames; 5867 seekcount = framenum - baseframe; 5868 } 5869 else 5870 { 5871 for (; i != deleteMap.end(); ++i) 5872 { 5873 if (i.key() >= baseframe) 5874 break; 5875 framenum = i.key(); 5876 } 5877 if (framenum == -1) 5878 framenum = 0; 5879 seekcount = baseframe - framenum; 5880 } 5881 return seekcount; 5518 5882 } 5519 5883 5520 5884 void NuppelVideoPlayer::HandleArbSeek(bool right) 5521 5885 { 5522 5886 if (seekamount == -2) 5523 5887 { 5524 QMap<long long, int>::Iterator i = deleteMap.begin(); 5525 long long framenum = -1; 5888 long long seekcount = CalcCutPointSeek(framesPlayed, right); 5526 5889 if (right) 5527 5890 { 5528 for (; i != deleteMap.end(); ++i) 5529 { 5530 if (i.key() > framesPlayed) 5531 { 5532 framenum = i.key(); 5533 break; 5534 } 5535 } 5536 if (framenum == -1) 5537 framenum = totalFrames; 5538 5539 fftime = framenum - framesPlayed; 5891 fftime = seekcount; 5540 5892 while (fftime > 0) 5541 5893 usleep(1000); 5542 5894 } 5543 5895 else 5544 5896 { 5545 for (; i != deleteMap.end(); ++i) 5546 { 5547 if (i.key() >= framesPlayed) 5548 break; 5549 framenum = i.key(); 5550 } 5551 if (framenum == -1) 5552 framenum = 0; 5553 5554 rewindtime = framesPlayed - framenum; 5897 rewindtime = seekcount; 5555 5898 while (rewindtime > 0) 5556 5899 usleep(1000); 5557 5900 } … … 5582 5925 UpdateEditSlider(); 5583 5926 } 5584 5927 5928 int NuppelVideoPlayer::GetCutStatus(long long testframe) const 5929 { 5930 int retval = 0; 5931 QMap<long long, int>::const_iterator i; 5932 i = deleteMap.find(testframe); 5933 if (i == deleteMap.end()) { 5934 // testframe is not an explicit cutpoint 5935 // See if it is in a deleted area 5936 if (IsInDelete(testframe)) 5937 retval = 1; 5938 } else { 5939 int direction = *i; 5940 if (direction == 0) 5941 retval = 2; 5942 else 5943 retval = 3; 5944 } 5945 5946 return retval; 5947 } 5948 5585 5949 bool NuppelVideoPlayer::IsInDelete(long long testframe) const 5586 5950 { 5587 5951 long long startpos = 0; -
mythtv/libs/libmythtv/NuppelVideoPlayer.h
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/NuppelVideoPlayer.h myth.20155.0309b/mythtv/libs/libmythtv/NuppelVideoPlayer.h
101 101 kDisplayTeletextMenu = 0x40, 102 102 }; 103 103 104 class DeletePointInfo 105 { 106 public: 107 DeletePointInfo() : 108 deleteframe(0), deletepoint(false), cut_after(false), direction(0) {} 109 110 long long deleteframe; 111 bool deletepoint; 112 bool cut_after; 113 int direction; 114 }; 115 116 104 117 class MPUBLIC NuppelVideoPlayer : public CC608Reader, public CC708Reader 105 118 { 106 119 friend class PlayerContext; 120 friend class GridEditCutpoints; 121 friend class TV; 107 122 108 123 public: 109 124 NuppelVideoPlayer(); … … 282 297 bool EnableEdit(void); 283 298 bool DoKeypress(QKeyEvent *e); 284 299 bool GetEditMode(void) const { return editmode; } 300 bool GetHideEdits(void) const { return hideedits; } 285 301 286 302 // Decoder stuff.. 287 303 VideoFrame *GetNextVideoFrame(bool allow_unsafe = true); … … 301 317 void ShutdownYUVResize(void); 302 318 void SaveScreenshot(void); 303 319 320 // Edit stuff 321 bool EditSeekToFrame(long long targetFrame); 322 void SetScreenGrabSizes(QSize normal, QSize small); 323 bool GetScreenGrabsOfCurrentFrame(QImage & normal, QImage &small); // Get current frame 324 325 326 void EditHandleClearMap(); 327 void EditHandleInvertMap(); 328 void EditHandleLoadCommSkip(); 329 330 void ShowEditRecordingGrid(); 331 304 332 // Reinit 305 333 void ReinitOSD(void); 306 334 void ReinitVideo(void); … … 420 448 bool PosMapFromEnc(unsigned long long start, 421 449 QMap<long long, long long> &posMap); 422 450 451 // Stuf for GridEditCutpoints 452 long long CalcCutPointSeek(long long baseframe, bool right); 453 // returns 454 // 0 - no cut 455 // 1 - is deleted 456 // 2 - cut left 457 // 3 - cut right 458 int GetCutStatus(long long testframe) const; 459 long long GetSeekAmount() { return seekamount; } 460 QString GetSeekAmountText() { return seekamounttext; } 461 423 462 protected: 424 463 void DisplayPauseFrame(void); 425 464 void DisplayNormalFrame(void); … … 502 541 void HandleSelect(bool allowSelectNear = false); 503 542 void HandleResponse(void); 504 543 544 DeletePointInfo GetDeletePointInfo(long long frame, bool allowSelectNear); 545 546 void SetupScreenGrab(); 547 void ClearScreenGrab(); 548 505 549 void UpdateTimeDisplay(void); 550 int GetSeekAmountPos() { return seekamountpos; } 506 551 void UpdateSeekAmount(bool up); 552 void SetHalfPageSize(int hp) { allow_pagesize = true; half_page = hp; } 553 void UpdateSeekAmountDisplay(void); 507 554 void UpdateEditSlider(void); 508 555 509 556 // Private A/V Sync Stuff … … 576 623 bool livetv; 577 624 bool watchingrecording; 578 625 bool editmode; 626 bool hideedits; 579 627 bool resetvideo; 580 628 bool using_null_videoout; 581 629 bool no_audio_in; … … 596 644 long long fftime; 597 645 /// 1..9 == keyframe..10 minutes. 0 == cut point 598 646 int seekamountpos; 647 /// Used for Grid Edit logic 648 bool allow_pagesize; 649 int half_page; 599 650 /// Seekable frame increment when not using exact seeks. 600 651 /// Usually equal to keyframedist. 601 652 int seekamount; 653 QString seekamounttext; // OSD seek units 602 654 /// Iff true we ignore seek amount and try to seek to an 603 655 /// exact frame ignoring key frame restrictions. 604 656 bool exactseeks; … … 737 789 QMutex yuv_lock; 738 790 QWaitCondition yuv_wait; 739 791 792 // EditGrid still image capture 793 ImgReSampleContext *grid_edit_image_scaler; 794 ImgReSampleContext *grid_edit_image_small_scaler; 795 unsigned char *grid_edit_image_buffer_yuv; 796 unsigned char *grid_edit_image_small_buffer_yuv; 797 unsigned char *grid_edit_image_buffer_rgb; 798 unsigned char *grid_edit_image_small_buffer_rgb; 799 int grid_edit_image_buffer_length; 800 int grid_edit_image_small_buffer_length; 801 QSize grid_edit_image_in_size; 802 QSize grid_edit_image_size; 803 QSize grid_edit_image_small_size; 804 740 805 // Filters 741 806 QMutex videofiltersLock; 742 807 QString videoFiltersForProgram; -
mythtv/libs/libmythtv/grideditcutpoints.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/grideditcutpoints.cpp myth.20155.0309b/mythtv/libs/libmythtv/grideditcutpoints.cpp
1 #include <math.h> 2 #include <unistd.h> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 #include <QApplication> 8 #include <QPainter> 9 #include <QFont> 10 #include <QKeyEvent> 11 #include <QEvent> 12 #include <QPixmap> 13 #include <QPaintEvent> 14 #include <QCursor> 15 #include <QImage> 16 #include <QLayout> 17 #include <QLabel> 18 #include <QDateTime> 19 #include <QRect> 20 21 #include "mythcontext.h" 22 #include "mythdbcon.h" 23 #include "grideditcutpoints.h" 24 #include "grideditimages.h" 25 #include "NuppelVideoPlayer.h" 26 27 void GridEditCutpoints::Run(NuppelVideoPlayer *player) 28 { 29 VERBOSE(VB_GENERAL, "Starting"); 30 gContext->addCurrentLocation("GridEditCutpoints"); 31 32 GridEditCutpoints *er = new GridEditCutpoints(gContext->GetMainWindow(), 33 player, "editrecording"); 34 35 if (er->isValid()) 36 { 37 er->Show(); 38 er->displayInitialFrame(); 39 er->exec(); 40 } 41 42 delete er; 43 44 gContext->removeCurrentLocation(); 45 VERBOSE(VB_GENERAL, "Ending"); 46 } 47 48 GridEditCutpoints::GridEditCutpoints(MythMainWindow *parent, 49 NuppelVideoPlayer *player, const char *name) 50 : MythThemedDialog(parent, "grideditcutpoints", "", name) 51 { 52 m_player = player; 53 m_images = new GridEditImages(this, player); 54 55 int i; 56 m_gridimagemain = NULL; 57 for (i = m_gridimages.minIndex(); i < m_gridimages.maxIndex(); i++) 58 { 59 m_gridimages[i] = NULL; 60 } 61 62 usedSubVideoCount=0; 63 64 QSize videoSizeMain, videoSizeSmall; 65 66 m_gridimagemain = getUIGridEditImageType("mainvideo"); 67 if (m_gridimagemain) 68 videoSizeMain = m_gridimagemain->getScreenArea().size(); 69 else 70 { 71 VERBOSE(VB_IMPORTANT, "FATAL: Couldn't find mainedit:mainvideo"); 72 return; 73 } 74 75 // Small version of main frame 76 m_gridimages[0] = getUIGridEditImageType("video0"); 77 78 for (i = 1; i < m_gridimages.maxIndex(); i++) 79 { 80 QString p = QString("videop%1").arg(i); 81 QString m = QString("videom%1").arg(i); 82 83 // Minus frame i 84 m_gridimages[-i] = getUIGridEditImageType(m); 85 if (m_gridimages[-i]) 86 { 87 QSize tmpVideoSizeSmall = m_gridimages[-i]->getScreenArea().size(); 88 if (videoSizeSmall.isValid() && videoSizeSmall != tmpVideoSizeSmall) 89 VERBOSE(VB_IMPORTANT, 90 QString("Multiple sizes found for edit videos (%1)").arg(m)); 91 else 92 videoSizeSmall = tmpVideoSizeSmall; 93 if (i > usedSubVideoCount) usedSubVideoCount=i; 94 } 95 96 m_gridimages[i] = getUIGridEditImageType(p); 97 if (m_gridimages[i]) 98 { 99 QSize tmpVideoSizeSmall = m_gridimages[i]->getScreenArea().size(); 100 if (videoSizeSmall.isValid() && videoSizeSmall != tmpVideoSizeSmall) 101 VERBOSE(VB_IMPORTANT, 102 QString("Multiple sizes found for edit videos (%1)").arg(p)); 103 else 104 videoSizeSmall = tmpVideoSizeSmall; 105 if (i > usedSubVideoCount) usedSubVideoCount=i; 106 } 107 } 108 109 imageScreenArea = m_gridimages[-usedSubVideoCount]->getOuterBorder(); 110 for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++) 111 if (m_gridimages[i]) 112 imageScreenArea = imageScreenArea.unite(m_gridimages[i]->getOuterBorder()); 113 114 m_images->SetVideoInfo(usedSubVideoCount, videoSizeMain, videoSizeSmall); 115 116 m_player->SetHalfPageSize(usedSubVideoCount); 117 m_slider = getUIGridEditSliderType("positionbar"); 118 if (!m_slider) 119 VERBOSE(VB_GENERAL, "Missing positionbar for GridEditCutpoints"); 120 121 // Get Status boxes 122 { 123 m_framenum = getUITextType("framenum"); 124 m_time = getUITextType("time"); 125 m_cutind = getUITextType("cutind"); 126 m_jumpstyle = getUITextType("jumpstyle"); 127 m_updatingind = getUITextType("updatingind"); 128 } 129 130 VERBOSE(VB_GENERAL, QString("main = (%1, %2) small = (%3, %4)") 131 .arg(videoSizeMain.width()).arg(videoSizeMain.height()) 132 .arg(videoSizeSmall.width()).arg(videoSizeSmall.height())); 133 134 slowMotionDirection = 1; // start off play forward 135 slowMotionActive = false; 136 readyForNextFrame = false; 137 slowMotionTimer = new QTimer(this); 138 QObject::connect(slowMotionTimer, SIGNAL(timeout()), 139 this, SLOT(updateSlowMotion())); 140 141 movingCutpoint = false; 142 // Create blank pixmaps... 143 144 updateBackground(); 145 146 updateStats(); 147 148 setNoErase(); 149 gContext->addListener(this); 150 151 updateForeground(); 152 } 153 154 GridEditCutpoints::~GridEditCutpoints() 155 { 156 if (m_images) 157 { 158 delete m_images; 159 m_images = NULL; 160 } 161 gContext->removeListener(this); 162 } 163 164 void GridEditCutpoints::displayInitialFrame() 165 { 166 refreshImages(); 167 refreshCutList(); 168 updateStats(); 169 SetUpdating(false); 170 } 171 172 void GridEditCutpoints::updateSlowMotion() 173 { 174 if (!slowMotionActive) 175 slowMotionTimer->stop(); 176 else if (readyForNextFrame && slowMotionDirection != 0) 177 { 178 readyForNextFrame=false; 179 180 if (slowMotionDirection > 0) 181 EditHandleRight(); 182 else if (slowMotionDirection < 0) 183 EditHandleLeft(); 184 } 185 } 186 187 188 void GridEditCutpoints::setSlowMotionSpeed() 189 { 190 // slowMotionDirection is max FPS 191 192 if (slowMotionDirection != 0) 193 { 194 int smd = slowMotionDirection; 195 if (smd < 0) smd = -smd; 196 int timeout = 1000 / smd; 197 198 slowMotionTimer->start(timeout); 199 } 200 SetUpdating(true, QString("%1 FPS max").arg(slowMotionDirection)); 201 } 202 203 204 void GridEditCutpoints::keyPressEvent(QKeyEvent *e) 205 { 206 // keyDown limits keyrepeats to prevent continued scrolling 207 // after key is released. Note: Qt's keycompress should handle 208 // this but will fail with fast key strokes and keyboard repeat 209 // enabled. Keys will not be marked as autorepeat and flood buffer. 210 // setFocusPolicy(QWidget::ClickFocus) in constructor is important 211 // or keyRelease events will not be received after a refocus. 212 213 bool handled = false; 214 215 QStringList actions; 216 gContext->GetMainWindow()->TranslateKeyPress("TV Editing", e, actions); 217 218 { 219 for (unsigned int i = 0; i < actions.size() && !handled; i++) 220 { 221 QString action = actions[i]; 222 handled = true; 223 224 if (action == "SELECT") 225 { 226 if (slowMotionActive) 227 { 228 slowMotionActive = false; 229 slowMotionTimer->stop(); 230 } 231 else if (movingCutpoint) 232 { 233 // Move cutpoint 234 m_player->DeleteMark(savedCutpoint); 235 m_player->AddMark(m_images->GetCurrentFrameNumber(), savedCutType); 236 movingCutpoint = false; 237 refreshCutList(); 238 refreshImages(); 239 } 240 else 241 handleSelect(); 242 } 243 else if (action == "PAUSE") 244 { 245 if (movingCutpoint) 246 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 247 "Moving Cutpoint", 248 "Slow Motion Unavailable when moving cutpoint"); 249 else if (slowMotionActive) 250 { 251 slowMotionActive = false; 252 slowMotionTimer->stop(); 253 } 254 } 255 else if (action == "SLOWMO") 256 { 257 if (movingCutpoint) 258 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 259 "Moving Cutpoint", 260 "Slow Motion Unavailable when moving cutpoint"); 261 else 262 { 263 if (slowMotionActive) 264 { 265 slowMotionActive = false; 266 slowMotionTimer->stop(); 267 } 268 else 269 { 270 slowMotionActive = true; 271 readyForNextFrame = true; 272 slowMotionDirection = 1; 273 274 // force to either 1 frame. 1/2 page or full page motion 275 int i; 276 // move to 1 frame if on cutpoint 277 for (i = 0; m_player->GetSeekAmountPos() < 2 && i < 10; i++) 278 m_player->UpdateSeekAmount(true); 279 280 // move to fullpage if higher 281 for (i = 0; m_player->GetSeekAmountPos() > 4 && i < 10; i++) 282 m_player->UpdateSeekAmount(false); 283 284 setSlowMotionSpeed(); 285 } 286 } 287 } 288 else if (action == "LEFT") 289 { 290 if (slowMotionActive) 291 { 292 slowMotionDirection--; 293 setSlowMotionSpeed(); 294 } 295 else 296 { 297 SetUpdating(true); 298 EditHandleLeft(); 299 } 300 } 301 else if (action == "RIGHT" ) 302 { 303 if (slowMotionActive) 304 { 305 slowMotionDirection++; 306 setSlowMotionSpeed(); 307 } 308 else 309 { 310 SetUpdating(true); 311 EditHandleRight(); 312 } 313 } 314 else if (action == "UP") 315 { 316 m_player->UpdateSeekAmount(true); 317 updateStats(); 318 } 319 else if (action == "DOWN") 320 { 321 if ((movingCutpoint || slowMotionActive) && m_player->GetSeekAmountPos() == 2) 322 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 323 "Moving Cutpoint", 324 "CutPoint skip Unavailable"); 325 else 326 { 327 m_player->UpdateSeekAmount(false); 328 updateStats(); 329 } 330 } 331 else if (action == "CLEARMAP") 332 { 333 if (movingCutpoint || slowMotionActive) 334 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 335 "Moving Cutpoint", 336 "Clear Cut Map Unavailable"); 337 else 338 { 339 SetUpdating(true); 340 m_player->EditHandleClearMap(); 341 refreshCutList(); 342 updateStats(); 343 } 344 } 345 else if (action == "INVERTMAP") 346 { 347 if (movingCutpoint || slowMotionActive) 348 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 349 "Moving Cutpoint", 350 "Invert Cut Map Unavailable"); 351 else 352 { 353 SetUpdating(true); 354 m_player->EditHandleInvertMap(); 355 refreshCutList(); 356 updateStats(); 357 } 358 } 359 else if (action == "LOADCOMMSKIP") 360 { 361 if (movingCutpoint || slowMotionActive) 362 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 363 "Moving Cutpoint", 364 "Load Comm Skip Map Unavailable"); 365 else 366 { 367 SetUpdating(true); 368 m_player->EditHandleLoadCommSkip(); 369 refreshCutList(); 370 updateStats(); 371 } 372 } 373 else if (action == "PREVCUT") 374 { 375 if (movingCutpoint || slowMotionActive) 376 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 377 "Moving Cutpoint", 378 "Prev Cut Unavailable"); 379 else 380 { 381 SetUpdating(true); 382 EditHandlePrevCut(); 383 } 384 } 385 else if (action == "NEXTCUT") 386 { 387 if (movingCutpoint || slowMotionActive) 388 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 389 "Moving Cutpoint", 390 "Next Cut Unavailable"); 391 else 392 { 393 SetUpdating(true); 394 EditHandleNextCut(); 395 } 396 } 397 else if (action == "BIGJUMPREW") 398 { 399 SetUpdating(true); 400 EditHandleBigJumpRew(); 401 } 402 else if (action == "BIGJUMPFWD") 403 { 404 SetUpdating(true); 405 EditHandleBigJumpFwd(); 406 } 407 else if (action == "ESCAPE" && movingCutpoint) 408 movingCutpoint = false; 409 else if (action == "ESCAPE" || action == "TOGGLEEDIT" || 410 action == "MENU") 411 escape(); 412 else 413 handled = false; 414 415 if (movingCutpoint) 416 SetUpdating(true, "Moving Cutpoint"); 417 else if (!slowMotionActive) 418 SetUpdating(false); 419 } 420 } 421 422 if (!handled) 423 MythDialog::keyPressEvent(e); 424 } 425 426 void GridEditCutpoints::EditHandleLeft(int seektype) 427 { 428 long long seekamount = m_player->GetSeekAmount(); 429 bool cutpointseek = false; 430 431 if (seektype == -2 || seekamount == -2) 432 cutpointseek = true; 433 else 434 { 435 // seektype == 1 for normal, 10 for bigjump 436 seekamount *= seektype; 437 } 438 439 if (seekamount < 0) // Invalid -- keyframe 440 seekamount = 1; 441 442 m_images->SeekLeft(seekamount, cutpointseek); 443 444 refreshImages(); 445 updateStats(); 446 } 447 448 void GridEditCutpoints::EditHandleRight(int seektype) 449 { 450 long long seekamount = m_player->GetSeekAmount(); 451 bool cutpointseek=false; 452 453 if (seektype == -2 || seekamount == -2) 454 cutpointseek = true; 455 else 456 { 457 // seektype == 1 for normal, 10 for bigjump 458 seekamount *= seektype; 459 } 460 461 if (seekamount < 0) // Invalid -- keyframe 462 seekamount = 1; 463 464 m_images->SeekRight(seekamount, cutpointseek); 465 466 refreshImages(); 467 updateStats(); 468 } 469 470 void GridEditCutpoints::handleSelect(void) 471 { 472 bool needupdate = false; 473 // add / update cutpoint 474 // -or- 475 // delete / flip / move cutpoint 476 477 // if no cut points on screen 478 // "Delete Before" 479 // "Delete After" 480 481 // if on existing cutpoint 482 // "Delete cutpoint" 483 // "Flip directions" 484 485 // FIXME 486 // if a cutpoint exists on the screen but not on the current frame 487 // "Move to current frame" 488 // "Add new" 489 490 FrameStats fs = m_images->GetMainFrameStats(); 491 DeletePointInfo dpi = m_player->GetDeletePointInfo(fs.frameNumber, true); 492 493 if (fs.cutInd >= 2) 494 { 495 QString title = ""; 496 QString message = "Cutpoint exists:"; 497 QStringList buttons; 498 buttons.append("Delete cutpoint?"); 499 buttons.append("Move cutpoint?"); 500 if (fs.cutInd == 2) 501 buttons.append("Flip directions (Cut After)?"); 502 else 503 buttons.append("Flip directions (Cut Before)?"); 504 505 DialogCode dc = MythPopupBox::ShowButtonPopup(gContext->GetMainWindow(), 506 title, message, buttons, kDialogCodeButton0); 507 508 if (dc != kDialogCodeRejected) 509 { 510 needupdate = true; 511 if (dc == kDialogCodeButton0) 512 // Delete cutpoint 513 m_player->DeleteMark(fs.frameNumber); 514 515 else if (dc == kDialogCodeButton1) 516 { 517 // Move cutpoint 518 savedCutpoint = fs.frameNumber; 519 savedCutType = m_player->deleteMap[fs.frameNumber]; 520 movingCutpoint = true; 521 // Ensure we're at least at 1 frame motion 522 int i; 523 for (i = 0; m_player->GetSeekAmountPos() < 2 && i < 10; i++) 524 m_player->UpdateSeekAmount(true); 525 526 } 527 else if (dc == kDialogCodeButton2) 528 // Flip 529 m_player->ReverseMark(fs.frameNumber); 530 } 531 } 532 else 533 { 534 QString title = ""; 535 QString message = "Insert New Cutpoint?"; 536 QStringList buttons; 537 buttons.append("Delete before this frame"); 538 buttons.append("Delete after this frame"); 539 DialogCode default_cut = (dpi.cut_after ? kDialogCodeButton1: kDialogCodeButton0); 540 DialogCode dc = MythPopupBox::ShowButtonPopup(gContext->GetMainWindow(), 541 title, message, buttons, default_cut); 542 543 if (dc != kDialogCodeRejected) 544 { 545 needupdate = true; 546 if (dc == kDialogCodeButton0) 547 // Delete left 548 m_player->AddMark(fs.frameNumber, MARK_CUT_END); 549 550 else if (dc == kDialogCodeButton1) 551 // Delete Right 552 m_player->AddMark(fs.frameNumber, MARK_CUT_START); 553 } 554 } 555 556 if (needupdate) 557 { 558 refreshCutList(); 559 refreshImages(); 560 } 561 } 562 563 void GridEditCutpoints::refreshImages() 564 { 565 m_images->refreshImages(m_gridimagemain, m_gridimages, false); 566 repaint(m_gridimagemain->getOuterBorder()); 567 repaint(imageScreenArea); 568 } 569 570 void GridEditCutpoints::refreshCutList() 571 { 572 m_images->refreshCutList(m_gridimagemain, m_gridimages); 573 refreshSlider(); 574 } 575 576 void GridEditCutpoints::refreshSlider() 577 { 578 if (!m_slider) 579 return; 580 581 m_slider->ClearAll(); 582 583 const int CUT_LEFT = 0; 584 const int CUT_RIGHT = 1; 585 586 long long startpos = 0; 587 long long endpos = 0; 588 589 int lastdirection = CUT_LEFT; 590 591 QMap<long long, int> & deleteMap = m_player->deleteMap; 592 QMap<long long, int>::Iterator i = deleteMap.begin(); 593 for (; i != deleteMap.end(); ++i) 594 { 595 long long frame = i.key(); 596 int direction = *i; 597 598 if (direction == CUT_LEFT) 599 { 600 endpos = frame; 601 m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber()); 602 603 startpos = frame; 604 lastdirection = CUT_LEFT; 605 } 606 else if (direction == CUT_RIGHT) 607 { 608 if (lastdirection == CUT_RIGHT) 609 { 610 // continuing within a cutpoint 611 endpos = frame; 612 m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber()); 613 } 614 615 startpos = frame; 616 lastdirection = CUT_RIGHT; 617 } 618 } 619 620 if (lastdirection == CUT_RIGHT) 621 { 622 // continuing within a cutpoint 623 endpos = m_images->GetMaxFrameNumber(); 624 m_slider->SetRange(startpos, endpos, m_images->GetMaxFrameNumber()); 625 } 626 } 627 628 void GridEditCutpoints::updateStats(bool forcerepaint) 629 { 630 int secs, frames, ss, mm, hh; 631 632 FrameStats fs = m_images->GetMainFrameStats(); 633 634 secs = (int)(fs.frameNumber / m_player->GetFrameRate()); 635 frames = fs.frameNumber - (int)(secs * m_player->GetFrameRate()); 636 637 ss = secs; 638 mm = ss / 60; 639 ss %= 60; 640 hh = mm / 60; 641 mm %= 60; 642 643 char timestr[128]; 644 sprintf(timestr, "%d:%02d:%02d.%02d", hh, mm, ss, frames); 645 646 char framestr[128]; 647 sprintf(framestr, "%lld", fs.frameNumber); 648 649 if (m_time) 650 { 651 m_time->SetText(timestr); 652 if (forcerepaint) 653 repaint(m_time->getScreenArea()); 654 } 655 if (m_framenum) 656 { 657 m_framenum->SetText(framestr); 658 if (forcerepaint) 659 repaint(m_framenum->getScreenArea()); 660 } 661 if (m_cutind) 662 { 663 switch (fs.cutInd) { 664 case 0: m_cutind->SetText(""); break; 665 case 1: m_cutind->SetText("Cut"); break; 666 case 2: m_cutind->SetText("Cut Before"); break; 667 case 3: m_cutind->SetText("Cut After"); break; 668 } 669 if (forcerepaint) 670 repaint(m_cutind->getScreenArea()); 671 } 672 673 // Don't need to force update this 674 if (m_jumpstyle) 675 m_jumpstyle->SetText(m_player->GetSeekAmountText()); 676 677 if (m_slider) 678 m_slider->SetPosition(fs.frameNumber, fs.maxFrameNumber); 679 680 } 681 682 void GridEditCutpoints::escape() 683 { 684 // Make sure we're on the right frame when we go back to 685 // Normal edit mode 686 unsetCursor(); 687 accept(); 688 } 689 690 void GridEditCutpoints::SetUpdating(bool active, QString text) 691 { 692 if (m_updatingind) 693 { 694 //VERBOSE(VB_GENERAL, QString("Updating to %1").arg(active)); 695 if (active) 696 { 697 m_updatingind->show(); 698 m_updatingind->SetText(text); 699 } 700 else 701 m_updatingind->hide(); 702 repaint(m_updatingind->getScreenArea()); 703 } 704 } 705 706 void GridEditCutpoints::cacheFramesAreReady() 707 { 708 if (slowMotionActive) 709 { 710 readyForNextFrame=true; 711 if (!slowMotionTimer->isActive()) 712 slowMotionTimer->start(0); 713 } 714 } 715 -
mythtv/libs/libmythtv/grideditcutpoints.h
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/grideditcutpoints.h myth.20155.0309b/mythtv/libs/libmythtv/grideditcutpoints.h
1 // -*- Mode: c++ -*- 2 #ifndef GRIDEDITCUTPOINTS_H_ 3 #define GRIDEDITCUTPOINTS_H_ 4 5 #include <qstring.h> 6 7 #include "libmyth/mythwidgets.h" 8 #include "uitypes.h" 9 10 #include "grideditimages.h" 11 12 using namespace std; 13 14 class QTimer; 15 class NuppelVideoPlayer; 16 class GridEditImages; 17 18 class MPUBLIC GridEditCutpoints : public MythThemedDialog 19 { 20 Q_OBJECT 21 22 public: 23 // Use this function to instantiate an GridEditCutpoints instance. 24 static void Run(NuppelVideoPlayer *player); 25 26 void refreshImages(); 27 void cacheFramesAreReady(); 28 bool isValid() { return ((usedSubVideoCount > 0) && (m_gridimagemain != NULL)); }; 29 30 protected: 31 GridEditCutpoints(MythMainWindow *parent, 32 NuppelVideoPlayer *player, const char *name = "GridEditCutpoints"); 33 ~GridEditCutpoints(); 34 35 void displayInitialFrame(); 36 37 void handleSelect(); 38 39 void updateStats(bool forcerepaint = false); 40 41 protected slots: 42 void escape(); 43 void updateSlowMotion(); 44 45 private: 46 void keyPressEvent(QKeyEvent *e); 47 48 // seektype == -2 - cutpoint seek 49 // seektype == 1 - normal seek 50 // seektype == 10 - large seek 51 void EditHandleLeft(int seektype = 1); 52 void EditHandleRight(int seektype = 1); 53 void EditHandlePrevCut() { EditHandleLeft(-2); }; 54 void EditHandleNextCut() { EditHandleRight(-2); }; 55 void EditHandleBigJumpRew() { EditHandleLeft(10); }; 56 void EditHandleBigJumpFwd() { EditHandleRight(10); }; 57 void setSlowMotionSpeed(); 58 void refreshCutList(); 59 void refreshSlider(); 60 61 void SetUpdating(bool active, QString text = "Updating"); 62 63 // Private Data 64 65 NuppelVideoPlayer *m_player; 66 GridEditImages *m_images; 67 68 int usedSubVideoCount; 69 myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> m_gridimages; 70 // The main Big image 71 UIGridEditImageType* m_gridimagemain; 72 73 74 long long savedCutpoint; 75 int savedCutType; 76 bool movingCutpoint; 77 78 UITextType *m_framenum; 79 UITextType *m_time; 80 UITextType *m_cutind; 81 UITextType *m_jumpstyle; 82 UITextType *m_updatingind; 83 84 UIGridEditSliderType *m_slider; 85 QTimer *slowMotionTimer; 86 int slowMotionDirection; 87 bool slowMotionActive; 88 bool readyForNextFrame; 89 90 QRect imageScreenArea; 91 }; 92 93 #endif -
mythtv/libs/libmythtv/grideditimages.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/grideditimages.cpp myth.20155.0309b/mythtv/libs/libmythtv/grideditimages.cpp
1 #include <math.h> 2 #include <unistd.h> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 #include <QApplication> 8 #include <QPainter> 9 #include <QFont> 10 #include <QKeyEvent> 11 #include <QEvent> 12 #include <QPixmap> 13 #include <QPaintEvent> 14 #include <QCursor> 15 #include <QImage> 16 #include <QLayout> 17 #include <QLabel> 18 #include <QDateTime> 19 #include <QRect> 20 21 #include "mythcontext.h" 22 #include "mythdbcon.h" 23 #include "grideditimages.h" 24 #include "grideditcutpoints.h" 25 #include "NuppelVideoPlayer.h" 26 27 #define FRAME_DEBUG 0 28 #define CACHE_DEBUG 0 29 30 GridEditImages::GridEditImages(GridEditCutpoints *editor, NuppelVideoPlayer *player) 31 { 32 m_editor = editor; 33 m_player = player; 34 usedSubVideoCount = 0; 35 36 lastmovewasright= true; 37 38 int i; 39 for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++) 40 { 41 stillFrames[i] = NULL; 42 stillFramesBig[i] = NULL; 43 cutFrames[i] = 0; 44 } 45 46 memset(cutFramesCache, 0, sizeof(cutFramesCache)); 47 memset(stillFramesCache, 0, sizeof(stillFramesCache)); 48 memset(stillFramesBigCache, 0, sizeof(stillFramesBigCache)); 49 stillFrameCacheCount = 0; 50 stillFramesCacheBase = 0; 51 52 // Get first frames... 53 stillMainFrameNumber = m_player->GetFramesPlayed(); 54 if (stillMainFrameNumber <= 0) 55 stillMainFrameNumber = 1; 56 57 // maxFrameNumber may be overridden if neccessary 58 maxFrameNumber = m_player->GetTotalFrameCount(); 59 maxFrameNumberNVP = m_player->GetTotalFrameCount(); 60 61 if (stillMainFrameNumber <= 0) 62 stillMainFrameNumber = 1; 63 64 if (stillMainFrameNumber > maxFrameNumber) 65 stillMainFrameNumber = maxFrameNumber; 66 67 getImagesTimer = new QTimer(this); 68 QObject::connect(getImagesTimer, SIGNAL(timeout()), 69 this, SLOT(updateAllFrames())); 70 71 72 } 73 74 GridEditImages::~GridEditImages() 75 { 76 emptyCache(); 77 clearStillFrames(); 78 m_player->EditSeekToFrame(stillMainFrameNumber); 79 } 80 81 QPixmap *GridEditImages::makeScaledPixmap(const QImage& qim, QSize sz) 82 { 83 QPixmap *retval; 84 if (qim.size() == sz) 85 { 86 retval = new QPixmap(sz); 87 QPainter p(retval); 88 p.drawImage(0, 0, qim); 89 } 90 else 91 { 92 retval = new QPixmap(sz); 93 retval->fill(Qt::black); 94 QPainter p(retval); 95 96 int tl_left = 0; 97 int tl_top = 0; 98 if (sz.width() > qim.width()) 99 tl_left += (sz.width() - qim.width()) / 2; 100 101 if (sz.height() > qim.height()) 102 tl_top += (sz.height() - qim.height()) / 2; 103 104 // VERBOSE(VB_GENERAL, QString("Size mismatch qim(%1, %2) != sz(%3, %4) Shift to (%5, %6)") 105 // .arg(qim.width()).arg(qim.height()) 106 // .arg(sz.width()).arg(sz.height()) 107 // .arg(tl_left).arg(tl_top)); 108 109 p.drawImage(tl_left, tl_top, qim); 110 } 111 return retval; 112 } 113 114 void GridEditImages::getMainStillFrame() 115 { 116 getSpecificFrame(0); 117 } 118 119 bool GridEditImages::getFrameIndexes(int newlevel) 120 { 121 // levels: 122 // 0 - onscreen frames 123 // 1 - precache frames 124 // 2 - fill-out-the buffer frames 125 126 if (newlevel > 2) 127 return false; 128 129 // This gets the upper and lower indexes of the frames we need to get. 130 // Note these indexes maybe negative 131 // Negative frames are before the main frame 132 // Frame #0 is the main frame 133 // Positive frames are after the main frame 134 135 // Basic initialization 136 // Doesn't go to absolute end because it slows down seeking 137 // when you go 1 frame left and right 138 frameIndexLeft = stillFrames.minIndex() + 4; 139 frameIndexRight = stillFrames.maxIndex() - 4; 140 getFutureFramesFirst = false; 141 142 if (newlevel == 0) // Current Display only 143 { 144 frameIndexLeft = -usedSubVideoCount; 145 frameIndexRight = usedSubVideoCount; 146 } 147 else 148 { 149 getFutureFramesFirst = lastmovewasright; 150 151 if (newlevel == 1) // PreCache only 152 { 153 // preCacheIndexLeft and Right are indexes for the frames to start and end on 154 frameIndexLeft = preCacheIndexLeft; 155 frameIndexRight = preCacheIndexRight; 156 } 157 } 158 159 // Make sure we don't fall of the front of the file 160 if (stillMainFrameNumber + frameIndexLeft <= 0) 161 frameIndexLeft = -(stillMainFrameNumber-1); 162 163 // ... or the back of the file 164 if (frameIndexRight > (maxFrameNumber - stillMainFrameNumber)) 165 frameIndexRight = (maxFrameNumber - stillMainFrameNumber); 166 167 #if CACHE_DEBUG 168 VERBOSE(VB_GENERAL, QString("Getting frames from %1 to %2 for level %3") 169 .arg(frameIndexLeft).arg(frameIndexRight).arg(newlevel)); 170 #endif 171 return true; 172 } 173 174 bool GridEditImages::getStillFrames(int maxcount) 175 { 176 // returns true if no more frames to get 177 178 // This will fill in all the missing frames in the cache 179 180 long long i; 181 if (getFutureFramesFirst && frameIndexLeft < 0) 182 { 183 // If we're filling out the cache and the last move was to the right 184 // grab future frames first before any past frames 185 for (i = 1; i <= frameIndexRight; i++) 186 if (getSpecificFrame(i)) 187 if (--maxcount == 0) return false; 188 } 189 190 // grab all appropriate frames 191 192 for (i = frameIndexLeft; i <= frameIndexRight; i++) 193 if (getSpecificFrame(i)) 194 if (--maxcount == 0) return false; 195 196 return true; 197 } 198 199 bool GridEditImages::getSpecificFrame(long long i) 200 { 201 // i is the index within the cache of frames 202 203 // If we're outside of the normal boundaries of the buffer, 204 // see if we've precached this frame 205 if (i < stillFrames.minIndex() || i > stillFrames.maxIndex()) 206 { 207 // First extra cached frame 208 if (stillFrameCacheCount == 0) 209 stillFramesCacheBase = stillMainFrameNumber + i; 210 211 int tmpi; 212 for (tmpi = 0; tmpi < stillFrameCacheCount; tmpi++) 213 { 214 long long tmpframe = (stillFramesCacheBase + tmpi); 215 if (tmpframe == stillMainFrameNumber + i) 216 return false; 217 } 218 219 // Check for cache overflow 220 if (stillFrameCacheCount >= MAX_SUB_VIDEOS) 221 { 222 VERBOSE(VB_GENERAL, QString("Cached too many videos. Max = %1").arg(MAX_SUB_VIDEOS)); 223 return false; 224 } 225 226 tmpi = stillFrameCacheCount++; 227 228 #if CACHE_DEBUG 229 VERBOSE(VB_GENERAL, QString("Caching frame %1, (frm# %2, index %3)") 230 .arg(tmpi).arg(stillMainFrameNumber + i) 231 .arg(i)); 232 #endif 233 234 getFrame(i, cutFramesCache[tmpi], stillFramesCache[tmpi], stillFramesBigCache[tmpi]); 235 return true; 236 } 237 else if (!stillFrames[i]) 238 { 239 getFrame(i, cutFrames[i], stillFrames[i], stillFramesBig[i]); 240 return true; 241 } 242 243 return false; 244 } 245 246 void GridEditImages::getFrame(long long i, 247 int &cutFrame, 248 QPixmap * &stillFrame, 249 QPixmap * &stillFrameBig) 250 { 251 // get this frame 252 long long targetFrame = stillMainFrameNumber + i; 253 254 if (!m_player->EditSeekToFrame(targetFrame)) 255 { 256 VERBOSE(VB_GENERAL, QString("Error seeking to Frame[%1] (frame # %2)") 257 .arg(i).arg(targetFrame)); 258 checkMaxFrameCount(); 259 260 stillFrameBig = new QPixmap(videoSizeMain); 261 stillFrameBig->fill(Qt::gray); 262 263 stillFrame = new QPixmap(videoSizeSmall); 264 stillFrame->fill(Qt::gray); 265 } 266 else 267 { 268 cutFrame = m_player->GetCutStatus(targetFrame); 269 QImage normal, small; 270 m_player->GetScreenGrabsOfCurrentFrame(normal, small); 271 272 stillFrameBig = makeScaledPixmap(normal, videoSizeMain); 273 stillFrame = makeScaledPixmap(small, videoSizeSmall); 274 275 #if FRAME_DEBUG 276 VERBOSE(VB_GENERAL, QString("stillFrames[%1] = %2 (%3)") 277 .arg(i) 278 .arg(targetFrame) 279 .arg(cutFrame)); 280 #endif 281 } 282 } 283 284 void GridEditImages::SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall) 285 { 286 usedSubVideoCount = vcount; 287 videoSizeMain = sizeMain; 288 videoSizeSmall = sizeSmall; 289 SetPreCache(1); 290 291 m_player->SetScreenGrabSizes(videoSizeMain, videoSizeSmall); 292 293 // start to grab the current images 294 getMainStillFrame(); 295 startFrameCaching(); 296 } 297 298 void GridEditImages::startFrameCaching() 299 { 300 frameCacheLevel=0; 301 getFrameIndexes(frameCacheLevel); 302 303 getImagesTimer->start(0); 304 } 305 306 void GridEditImages::SetPreCache(long long pccount) 307 { 308 preCacheIndexLeft = pccount - usedSubVideoCount; 309 preCacheIndexRight = pccount + usedSubVideoCount; 310 } 311 312 void GridEditImages::updateAllFrames() 313 { 314 // getStillFrames() returns 'true' on the next call after it's gotten all requested frames 315 316 if (getStillFrames(1)) 317 { 318 // If we've pre-cached the next screen of frames, tell the editor about it 319 if (frameCacheLevel == 1) 320 m_editor->cacheFramesAreReady(); 321 322 frameCacheLevel++; 323 if (getFrameIndexes(frameCacheLevel)) 324 getStillFrames(1); 325 else 326 stopFrameCaching(); 327 } 328 m_editor->refreshImages(); 329 } 330 331 void GridEditImages::clearStillFrames() 332 { 333 int i; 334 for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++) 335 { 336 if (stillFrames[i]) 337 { 338 delete stillFrames[i]; 339 stillFrames[i] = NULL; 340 } 341 if (stillFramesBig[i]) 342 { 343 delete stillFramesBig[i]; 344 stillFramesBig[i] = NULL; 345 } 346 cutFrames[i] = 0; 347 } 348 } 349 350 bool GridEditImages::shiftStillFramesLeft(long long offset) 351 { 352 if (offset > 2 * stillFrames.maxIndex()) 353 { 354 // Dump all cached data and re-get it 355 clearStillFrames(); 356 } 357 else if (offset < 0) 358 { 359 VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset)); 360 // Dump all cached data and re-get it 361 clearStillFrames(); 362 offset = 0; 363 } 364 else if (offset != 0) 365 { 366 // Shift backwards in the stream by offset 367 368 // All frames will actually shift to the right. 369 // frame 'n' will become frame 'n+1' 370 // frame stillFrameMinus[1] will become mainframe 371 // frame stillFramePlus[max] will drop off 372 373 // shove extra frames into the excess space above usedSubVideos 374 375 if (offset >= stillMainFrameNumber) 376 offset = (stillMainFrameNumber-1); 377 378 // printStillFrameStats("Before SL"); 379 int i,j; 380 int minIndex = stillFrames.minIndex(); 381 int maxIndex = stillFrames.maxIndex(); 382 for (i = 0; i < offset; i++) 383 { 384 385 if (stillFrames[maxIndex]) 386 { 387 delete stillFrames[maxIndex]; 388 delete stillFramesBig[maxIndex]; 389 } 390 391 for (j = maxIndex; j > minIndex; j--) { 392 stillFrames[j] = stillFrames[j-1]; 393 stillFramesBig[j] = stillFramesBig[j-1]; 394 cutFrames[j] = cutFrames[j-1]; 395 } 396 397 stillFrames[minIndex] = NULL; 398 stillFramesBig[minIndex] = NULL; 399 cutFrames[minIndex] = 0; 400 } 401 402 // printStillFrameStats("After SL"); 403 404 } 405 406 stillMainFrameNumber -= offset; 407 if (stillMainFrameNumber < 1) 408 stillMainFrameNumber = 1; 409 410 emptyCache(); 411 412 return (stillFramesBig[0] != NULL); 413 } 414 415 bool GridEditImages::shiftStillFramesRight(long long offset) 416 { 417 //VERBOSE(VB_GENERAL, QString("Offset = %1").arg(offset)); 418 if (offset > 2 * stillFrames.maxIndex()) 419 { 420 // Dump all cached data and re-get it 421 clearStillFrames(); 422 } 423 else if (offset < 0) 424 { 425 VERBOSE(VB_IMPORTANT, QString("Offset (%1) < 0").arg(offset)); 426 // Dump all cached data and re-get it 427 clearStillFrames(); 428 offset = 0; 429 } 430 else if (offset != 0) 431 { 432 433 // Shift forwards in the stream by offset 434 435 // All frames will actually shift to the left. 436 // frame 'n' will become frame 'n-1' 437 // frame stillFramePlus[1] will become mainframe 438 // frame stillFrameMinus[max] will drop off 439 440 // shove extra frames into the excess space above usedSubVideos 441 442 if (stillMainFrameNumber + offset > maxFrameNumber) 443 { 444 offset = (maxFrameNumber - stillMainFrameNumber); 445 VERBOSE(VB_GENERAL, QString("new Offset = %1").arg(offset)); 446 } 447 //printStillFrameStats("Before SR"); 448 449 int i,j; 450 int minIndex = stillFrames.minIndex(); 451 int maxIndex = stillFrames.maxIndex(); 452 453 for (i = 0; i < offset; i++) 454 { 455 if (stillFrames[minIndex]) 456 { 457 delete stillFrames[minIndex]; 458 delete stillFramesBig[minIndex]; 459 } 460 461 for (j = minIndex; j < maxIndex; j++) { 462 stillFrames[j] = stillFrames[j+1]; 463 stillFramesBig[j] = stillFramesBig[j+1]; 464 cutFrames[j] = cutFrames[j+1]; 465 } 466 467 stillFrames[maxIndex] = NULL; 468 stillFramesBig[maxIndex] = NULL; 469 cutFrames[maxIndex] = 0; 470 } 471 472 //printStillFrameStats("After SR"); 473 474 } 475 stillMainFrameNumber += offset; 476 if (stillMainFrameNumber > maxFrameNumber ) 477 stillMainFrameNumber = maxFrameNumber; 478 479 emptyCache(); 480 481 return (stillFramesBig[0] != NULL); 482 } 483 484 void GridEditImages::emptyCache() 485 { 486 #if CACHE_DEBUG 487 if (stillFrameCacheCount > 0) 488 { 489 long long minindex = (stillFramesCacheBase - stillMainFrameNumber); 490 long long maxindex = (stillFramesCacheBase+stillFrameCacheCount-1) - stillMainFrameNumber; 491 VERBOSE(VB_GENERAL, QString("emptying %1 frames (%2 - %3) into [%4] - [%5] ") 492 .arg(stillFrameCacheCount) 493 .arg(stillFramesCacheBase) 494 .arg(stillFramesCacheBase+(stillFrameCacheCount-1)) 495 .arg(minindex).arg(maxindex)); 496 } 497 #endif 498 int i; 499 for (i = 0; i < stillFrameCacheCount; i++) 500 { 501 long long tmpframe = stillFramesCacheBase + i; 502 long long frameIndex = tmpframe - stillMainFrameNumber; 503 504 // frameIndex is the index matching stillFramesCache[i] to stillFrames[frameIndex] 505 // If frameIndex is within the stillFrames range, then use this frame 506 // otherwise delete it 507 508 if (frameIndex >= stillFrames.minIndex() && frameIndex <= stillFrames.maxIndex()) 509 { 510 // move cache data into normal arrays. 511 if (stillFrames[frameIndex]) 512 { 513 VERBOSE(VB_GENERAL, QString("Frame %1 index %2 already exists") 514 .arg(tmpframe).arg(frameIndex)); 515 // Can't move it -- the destination exists 516 delete stillFramesCache[i]; 517 delete stillFramesBigCache[i]; 518 } 519 else 520 { 521 cutFrames[frameIndex] = cutFramesCache[i]; 522 stillFrames[frameIndex] = stillFramesCache[i]; 523 stillFramesBig[frameIndex] = stillFramesBigCache[i]; 524 } 525 } 526 else 527 { 528 delete stillFramesCache[i]; 529 delete stillFramesBigCache[i]; 530 } 531 cutFramesCache[i]=0; 532 stillFramesCache[i] = NULL; 533 stillFramesBigCache[i] = NULL; 534 } 535 stillFrameCacheCount = 0; 536 } 537 538 void GridEditImages::printStillFrameStats(QString caption) 539 { 540 int i; 541 // Debug info for frame cache 542 QString foundframes= caption + " Found Frames: "; 543 544 for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++) 545 if (stillFrames[i]) 546 foundframes += QString("%1 ").arg(i); 547 548 VERBOSE(VB_GENERAL, foundframes); 549 } 550 551 void GridEditImages::refreshCutList(UIGridEditImageType* gridimagemain, 552 myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> &gridimages) 553 { 554 int i; 555 for (i = stillFrames.minIndex(); i <= stillFrames.maxIndex(); i++) 556 { 557 if (stillFrames[i]) 558 { 559 cutFrames[i] = m_player->GetCutStatus(stillMainFrameNumber+i); 560 if (gridimages[i]) 561 gridimages[i]->setCutStatus(cutFrames[i]); 562 } 563 } 564 565 gridimagemain->setCutStatus(cutFrames[0]); 566 } 567 568 bool GridEditImages::refreshImages(UIGridEditImageType* gridimagemain, 569 myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> &gridimages, 570 bool mainFrameOnly) 571 { 572 // VERBOSE(VB_GENERAL, "Start"); 573 bool alldone = true; 574 if (!stillFramesBig[0]) 575 VERBOSE(VB_GENERAL, QString("Null Big Main frame %1").arg(stillMainFrameNumber)); 576 gridimagemain->setPixmap(stillFramesBig[0], 577 stillMainFrameNumber, 578 cutFrames[0]); 579 580 if (mainFrameOnly && gridimages[0]) 581 gridimages[0]->setPixmap(stillFrames[0], 582 stillMainFrameNumber, 583 cutFrames[0]); 584 585 if (!mainFrameOnly) 586 { 587 int i; 588 for (i = -usedSubVideoCount; i <= usedSubVideoCount; i++) 589 { 590 if (stillFrames[i] == NULL) 591 alldone = false; 592 if (gridimages[i]) 593 gridimages[i]->setPixmap(stillFrames[i], 594 (stillMainFrameNumber + i), 595 cutFrames[i]); 596 } 597 } 598 599 // VERBOSE(VB_GENERAL, "Finish"); 600 return alldone; 601 } 602 603 604 // Back up x frames 605 void GridEditImages::SeekLeft(long long seekamount, bool cutpointseek) 606 { 607 lastmovewasright = false; 608 stopFrameCaching(); 609 610 if (cutpointseek) 611 seekamount = m_player->CalcCutPointSeek(stillMainFrameNumber, false); 612 613 //VERBOSE(VB_GENERAL, QString("SeekLeft %1, cutpoint = %2").arg(seekamount).arg(cutpointseek)); 614 615 if (cutpointseek) 616 SetPreCache(-1); 617 else 618 SetPreCache(-seekamount); 619 620 if (!shiftStillFramesLeft(seekamount)) 621 { 622 //VERBOSE(VB_GENERAL, QString("shiftStillFramesLeft(%1) == false") 623 // .arg(seekamount)); 624 // Need to grab the main frame 625 626 getMainStillFrame(); 627 } 628 629 startFrameCaching(); 630 } 631 632 void GridEditImages::SeekRight(long long seekamount, bool cutpointseek) 633 { 634 lastmovewasright = true; 635 stopFrameCaching(); 636 637 if (cutpointseek) 638 seekamount = m_player->CalcCutPointSeek(stillMainFrameNumber, true); 639 640 //VERBOSE(VB_GENERAL, QString("SeekRight %1, cutpoint = %2").arg(seekamount).arg(cutpointseek)); 641 642 if (cutpointseek) 643 SetPreCache(1); 644 else 645 SetPreCache(seekamount); 646 647 if (!shiftStillFramesRight(seekamount)) 648 { 649 //VERBOSE(VB_GENERAL, QString("shiftStillFramesLeft(%1) == false") 650 // .arg(seekamount)); 651 // Need to grab the main frame 652 653 getMainStillFrame(); 654 } 655 656 startFrameCaching(); 657 } 658 659 void GridEditImages::checkMaxFrameCount() 660 { 661 long long tfc = m_player->GetTotalFrameCount(); 662 if (tfc != maxFrameNumberNVP) 663 { 664 VERBOSE(VB_GENERAL, QString("Updating: tfc %1, mfn %2, mfnNVP %3") 665 .arg(tfc).arg(maxFrameNumber).arg(maxFrameNumberNVP)); 666 // Check to see if things changed 667 maxFrameNumber = tfc; 668 maxFrameNumberNVP = tfc; 669 } 670 } 671 672 FrameStats GridEditImages::GetMainFrameStats() 673 { 674 FrameStats result; 675 676 result.frameNumber = stillMainFrameNumber; 677 result.cutInd = cutFrames[0]; 678 result.maxFrameNumber = maxFrameNumber; 679 680 return result; 681 } 682 -
mythtv/libs/libmythtv/grideditimages.h
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/grideditimages.h myth.20155.0309b/mythtv/libs/libmythtv/grideditimages.h
1 // -*- Mode: c++ -*- 2 #ifndef GRIDEDITIMAGES_H_ 3 #define GRIDEDITIMAGES_H_ 4 5 #include <qstring.h> 6 7 #include "libmyth/mythwidgets.h" 8 9 using namespace std; 10 11 class QTimer; 12 class NuppelVideoPlayer; 13 class GridEditCutpoints; 14 15 #define MAX_SUB_VIDEOS 25 16 17 // Simple class to allow array indexing from -MAX_SUB_VIDEOS to +MAX_SUB_VIDEOS 18 template<class T, int COUNT> class myArray 19 { 20 public: 21 myArray() { memset(_array, 0, sizeof(_array));}; 22 23 T& operator[](int i) { return _array[COUNT+i]; }; 24 int minIndex() const { return -COUNT; }; 25 int maxIndex() const { return COUNT; }; 26 27 private: 28 T _array[2*COUNT+1]; 29 }; 30 31 class FrameStats 32 { 33 public: 34 long long frameNumber; 35 int cutInd; 36 long long maxFrameNumber; 37 }; 38 39 class MPUBLIC GridEditImages : public QObject 40 { 41 Q_OBJECT 42 43 public: 44 GridEditImages(GridEditCutpoints *er, NuppelVideoPlayer *player); 45 ~GridEditImages(); 46 47 void refreshCutList(UIGridEditImageType* gridimagemain, 48 myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> &gridimages); 49 50 // return true if anything changed 51 bool refreshImages(UIGridEditImageType* gridimagemain, 52 myArray<UIGridEditImageType*, MAX_SUB_VIDEOS> &gridimages, 53 bool mainFrameOnly); 54 55 void SeekLeft(long long seekamount, bool cutpointseek = false); 56 void SeekRight(long long seekamount, bool cutpointseek = false); 57 58 FrameStats GetMainFrameStats(); 59 long long GetCurrentFrameNumber() const { return stillMainFrameNumber; } 60 long long GetMaxFrameNumber() const { return maxFrameNumber; } 61 62 void SetVideoInfo(int vcount, QSize sizeMain, QSize sizeSmall); 63 64 protected slots: 65 void updateAllFrames(); 66 67 private: 68 // Private functions 69 void clearStillFrames(); 70 void printStillFrameStats(QString caption); 71 void checkMaxFrameCount(); 72 73 // 'newlevel' paramter for getStillFrames(): 74 // 0 = get on screen Frames only 75 // 1 = get preCache Frames only 76 // 2 = get any necessary frames 77 // 3 = done 78 bool getFrameIndexes(int newlevel); 79 80 bool getStillFrames(int maxcount = 1000); 81 void getMainStillFrame(); 82 bool getSpecificFrame(long long frameindex); 83 void getFrame(long long i, int &cutFrame, QPixmap* &stillFrame, QPixmap* &stillFrameBig); 84 void emptyCache(); 85 86 // return true if anything changed 87 bool shiftStillFramesLeft(long long offset); 88 bool shiftStillFramesRight(long long offset); 89 void startFrameCaching(); 90 void stopFrameCaching() { getImagesTimer->stop(); }; 91 92 QPixmap *makeScaledPixmap(const QImage& qim, QSize sz); 93 94 void SetPreCache(long long pccount); 95 96 // Private data 97 // These frames are in the cutlist 98 // 0 == not cut 99 // 1 == cut 100 // 2 == cutpoint (cut left) 101 // 3 == cutpoint (cut right) 102 myArray<int, MAX_SUB_VIDEOS> cutFrames; 103 myArray<QPixmap *, MAX_SUB_VIDEOS> stillFrames; 104 myArray<QPixmap *, MAX_SUB_VIDEOS> stillFramesBig; 105 106 // pre-caching large seek amounts 107 // (i.e. while seeking +5 seconds, these are places to store the to-be-displayed data) 108 109 int cutFramesCache[MAX_SUB_VIDEOS]; 110 QPixmap *stillFramesCache[MAX_SUB_VIDEOS]; 111 QPixmap *stillFramesBigCache[MAX_SUB_VIDEOS]; 112 int stillFrameCacheCount; 113 long long stillFramesCacheBase; // Frame # for index[0] 114 115 QSize videoSizeMain; 116 QSize videoSizeSmall; 117 int usedSubVideoCount; 118 long long preCacheIndexLeft; 119 long long preCacheIndexRight; 120 long long frameIndexLeft; 121 long long frameIndexRight; 122 bool lastmovewasright; 123 bool getFutureFramesFirst; 124 int frameCacheLevel; 125 126 long long stillMainFrameNumber; // frame number for big still picture 127 long long currentFrameNumberNVP; // frame number the NVP should be on 128 long long maxFrameNumber; // max frame number override for NVP 129 long long maxFrameNumberNVP; // Original NVP number 130 131 GridEditCutpoints *m_editor; 132 NuppelVideoPlayer *m_player; 133 134 QTimer *getImagesTimer; 135 136 }; 137 138 #endif -
mythtv/libs/libmythtv/libmythtv.pro
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/libmythtv.pro myth.20155.0309b/mythtv/libs/libmythtv/libmythtv.pro
363 363 # Misc. frontend 364 364 HEADERS += guidegrid.h infostructs.h 365 365 HEADERS += ttfont.h 366 HEADERS += grideditcutpoints.h grideditimages.h 366 367 SOURCES += guidegrid.cpp infostructs.cpp 367 368 SOURCES += ttfont.cpp 369 SOURCES += grideditcutpoints.cpp grideditimages.cpp 368 370 369 371 using_mheg { 370 372 # DSMCC stuff -
mythtv/libs/libmythtv/tv_play.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/tv_play.cpp myth.20155.0309b/mythtv/libs/libmythtv/tv_play.cpp
28 28 #include "remoteencoder.h" 29 29 #include "remoteutil.h" 30 30 #include "guidegrid.h" 31 #include "grideditcutpoints.h" 31 32 //#include "progfind.h" 32 33 #include "NuppelVideoPlayer.h" 33 34 #include "programinfo.h" … … 573 574 REG_KEY("TV Editing", "BIGJUMPFWD", "Jump forward 10x the normal amount", 574 575 ">,."); 575 576 REG_KEY("TV Editing", "TOGGLEEDIT", "Exit out of Edit Mode", "E"); 577 REG_KEY("TV Editing", "SLOWMO", "Slow Motion Play", "Ctrl+P"); 578 REG_KEY("TV Editing", "PAUSE", "Pause", "P"); 576 579 577 580 /* Teletext keys */ 578 581 REG_KEY("Teletext Menu", "NEXTPAGE", "Next Page", "Down"); … … 3232 3235 if (editmode) 3233 3236 { 3234 3237 actx->LockDeleteNVP(__FILE__, __LINE__); 3238 if (actx->nvp && actx->nvp->GetHideEdits()) 3239 { 3240 actx->UnlockDeleteNVP(__FILE__, __LINE__); 3241 return; 3242 } 3235 3243 if (actx->nvp && !actx->nvp->DoKeypress(e)) 3236 3244 editmode = actx->nvp->GetEditMode(); 3237 3245 actx->UnlockDeleteNVP(__FILE__, __LINE__); … … 7699 7707 qApp->postEvent(myWindow, me); 7700 7708 } 7701 7709 7710 void TV::ShowEditRecordingGrid() 7711 { 7712 // post the request to the main UI thread 7713 // it will be caught in eventFilter and processed as CustomEvent 7714 // this will create the program guide window (widget) 7715 // on the main thread and avoid a deadlock on Win32 7716 7717 VERBOSE(VB_GENERAL, "Starting Grid Edit"); 7718 QString message = QString("START_EDIT"); 7719 MythEvent* me = new MythEvent(message); 7720 qApp->postEvent(myWindow, me); 7721 } 7722 7702 7723 void TV::ChangeVolume(PlayerContext *ctx, bool up) 7703 7724 { 7704 7725 ctx->LockDeleteNVP(__FILE__, __LINE__); … … 8346 8367 DoEditSchedule(editType); 8347 8368 } 8348 8369 8370 if (message.left(10) == "START_EDIT") 8371 { 8372 const PlayerContext *mctx = 8373 GetPlayerReadLock(0, __FILE__, __LINE__); 8374 mctx->LockDeleteNVP(__FILE__, __LINE__); 8375 if (mctx->nvp) 8376 mctx->nvp->ShowEditRecordingGrid(); 8377 8378 mctx->UnlockDeleteNVP(__FILE__, __LINE__); 8379 ReturnPlayerLock(mctx); 8380 } 8381 8349 8382 if (message.left(14) == "COMMFLAG_START") 8350 8383 { 8351 8384 QString evchanid = QString::null; -
mythtv/libs/libmythtv/tv_play.h
diff -r -u -N -X diff.exclude.noxml -x myth.20155.0309a -x myth.20155.0309b myth.20155.0309a/mythtv/libs/libmythtv/tv_play.h myth.20155.0309b/mythtv/libs/libmythtv/tv_play.h
199 199 void setInPlayList(bool setting) { inPlaylist = setting; } 200 200 void setUnderNetworkControl(bool setting) { underNetworkControl = setting; } 201 201 202 void ShowEditRecordingGrid(); 202 203 void ShowNoRecorderDialog(const PlayerContext*, 203 204 NoRecorderMsg msgType = kNoRecorders); 204 205 void FinishRecording(int player_idx); ///< Finishes player's recording