MythTV  master
cutter.cpp
Go to the documentation of this file.
1 
2 #include "cutter.h"
3 
4 #include <algorithm> // for min
5 using namespace std;
6 
7 #include <QMap> // for QMap
8 
9 #include "mythlogging.h"
10 
12 {
13  // Break each cut into two parts, the first for
14  // the player and the second for the transcode loop.
15  frm_dir_map_t remainingCutList;
16  int64_t start = 0;
17  int64_t leadinLength = 0;
18 
19  m_tracker.SetPlayerContext(ctx);
20  m_foreshortenedCutList.clear();
21 
22  for (auto it = deleteMap.begin(); it != deleteMap.end(); ++it)
23  {
24  switch(it.value())
25  {
26  case MARK_CUT_START:
27  m_foreshortenedCutList[it.key()] = MARK_CUT_START;
28  start = it.key();
29  break;
30 
31  case MARK_CUT_END:
32  leadinLength = min((int64_t)(it.key() - start),
33  (int64_t)MAXLEADIN);
34  if (leadinLength >= MINCUT)
35  {
36  m_foreshortenedCutList[it.key() - leadinLength + 2] =
38  remainingCutList[it.key() - leadinLength + 1] =
40  remainingCutList[it.key()] = MARK_CUT_END;
41  }
42  else
43  {
44  // Cut too short to use new method.
45  m_foreshortenedCutList[it.key()] = MARK_CUT_END;
46  }
47  break;
48 
49  default:
50  // Ignore all other mark types.
51  break;
52  }
53  }
54 
55  m_tracker.SetMap(remainingCutList);
56 }
57 
59 {
60  return m_foreshortenedCutList;
61 }
62 
63 void Cutter::Activate(float v2a, int64_t total)
64 {
65  m_active = true;
66  m_audioFramesPerVideoFrame = v2a;
67  m_totalFrames = total;
68  m_videoFramesToCut = 0;
69  m_audioFramesToCut = 0;
70  m_tracker.TrackerReset(0);
71 }
72 
73 void Cutter::NewFrame(int64_t currentFrame)
74 {
75  if (m_active)
76  {
77  if (m_videoFramesToCut == 0)
78  {
79  uint64_t jumpTo = 0;
80 
81  if (m_tracker.TrackerWantsToJump(currentFrame, jumpTo))
82  {
83  // Reset the tracker and work out how much video and audio
84  // to drop
85  m_tracker.TrackerReset(jumpTo);
86  m_videoFramesToCut = jumpTo - currentFrame;
87  m_audioFramesToCut += llroundf(m_videoFramesToCut *
88  m_audioFramesPerVideoFrame);
89  LOG(VB_GENERAL, LOG_INFO,
90  QString("Clean cut: discarding frame from %1 to %2: "
91  "vid %3 aud %4")
92  .arg(currentFrame).arg((long)jumpTo)
93  .arg(m_videoFramesToCut)
94  .arg(m_audioFramesToCut));
95  }
96  }
97  }
98 }
99 
101 {
102  if (m_videoFramesToCut == 0)
103  {
104  return false;
105  }
106 
107  // We are inside a cut. Inhibit use of this frame
108  m_videoFramesToCut--;
109 
110  if(m_videoFramesToCut == 0)
111  {
112  LOG(VB_GENERAL, LOG_INFO,
113  QString("Clean cut: end of video cut; audio frames left "
114  "to cut %1") .arg(m_audioFramesToCut));
115  }
116 
117  return true;
118 }
119 
120 bool Cutter::InhibitUseAudioFrames(int64_t frames, long *totalAudio)
121 {
122  int64_t delta = m_audioFramesToCut - frames;
123  if (delta < 0)
124  delta = -delta;
125 
126  if (m_audioFramesToCut == 0)
127  {
128  return false;
129  }
130  if (delta < m_audioFramesToCut)
131  {
132  // Drop the packet containing these frames if doing
133  // so gets us closer to zero left to drop
134  m_audioFramesToCut -= frames;
135  if(m_audioFramesToCut == 0)
136  {
137  LOG(VB_GENERAL, LOG_INFO,
138  QString("Clean cut: end of audio cut; vidio frames left "
139  "to cut %1") .arg(m_videoFramesToCut));
140  }
141  return true;
142  }
143 
144  // Don't drop this packet even though we still have frames to cut,
145  // because doing so would put us further out. Instead, inflate the
146  // callers record of how many audio frames have been output.
147  *totalAudio += m_audioFramesToCut;
148  m_audioFramesToCut = 0;
149  LOG(VB_GENERAL, LOG_INFO,
150  QString("Clean cut: end of audio cut; vidio frames left to "
151  "cut %1") .arg(m_videoFramesToCut));
152  return false;
153 }
154 
156 {
157  if (m_audioFramesToCut > 0)
158  {
159  // If the cutter is in the process of dropping audio then
160  // it is better to drop more audio rather than insert a dummy frame
161  m_audioFramesToCut += llroundf(m_audioFramesPerVideoFrame);
162  return true;
163  }
164  return false;
165 }
166 
168 {
169  if (m_audioFramesToCut > llroundf(m_audioFramesPerVideoFrame))
170  {
171  // If the cutter is in the process of dropping audio and the
172  // amount to drop is sufficient then we can drop less
173  // audio rather than drop a frame
174  m_audioFramesToCut -= llroundf(m_audioFramesPerVideoFrame);
175 
176  // But if it's a frame we are supposed to drop anyway, still do so,
177  // and record that we have
178  if (m_videoFramesToCut > 0)
179  {
180  m_videoFramesToCut-- ;
181  return false;
182  }
183  return true;
184  }
185  return false;
186 }
187 
188 /* vim: set expandtab tabstop=4 shiftwidth=4: */
189 
Cutter::Activate
void Activate(float v2a, int64_t total)
Definition: cutter.cpp:63
Cutter::InhibitDummyFrame
bool InhibitDummyFrame(void)
Definition: cutter.cpp:155
MARK_CUT_END
@ MARK_CUT_END
Definition: programtypes.h:55
cutter.h
arg
arg(title).arg(filename).arg(doDelete))
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:82
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
Cutter::AdjustedCutList
frm_dir_map_t AdjustedCutList() const
Definition: cutter.cpp:58
mythlogging.h
Cutter::NewFrame
void NewFrame(int64_t currentFrame)
Definition: cutter.cpp:73
Cutter::InhibitDropFrame
bool InhibitDropFrame(void)
Definition: cutter.cpp:167
Cutter::InhibitUseAudioFrames
bool InhibitUseAudioFrames(int64_t frames, long *totalAudio)
Definition: cutter.cpp:120
MARK_CUT_START
@ MARK_CUT_START
Definition: programtypes.h:56
PlayerContext
Definition: playercontext.h:48
Cutter::InhibitUseVideoFrame
bool InhibitUseVideoFrame(void)
Definition: cutter.cpp:100
Cutter::SetCutList
void SetCutList(frm_dir_map_t &deleteMap, PlayerContext *ctx)
Definition: cutter.cpp:11