1 /***************************************************************************
2     \file stillimage.cpp
3     \author eumagga0x2a     @mailbox.org
4     \brief Duplicate frame for a given duration
5  ***************************************************************************/
6 
7 /***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #include "ADM_default.h"
17 #include "ADM_vidMisc.h"
18 #include "ADM_coreVideoFilter.h"
19 #include "DIA_coreToolkit.h"
20 #include "DIA_factory.h"
21 
22 #include "confStillimage.h"
23 #include "confStillimage_desc.cpp"
24 
25 #if 1
26     #define aprintf(...) {}
27 #else
28     #define aprintf printf
29 #endif
30 
31 /**
32     \class stillimage
33 */
34 class stillimage : public ADM_coreVideoFilter
35 {
36 protected:
37     configuration       params;
38     uint64_t            from, begin, end;
39     uint64_t            timeIncrement;
40     uint32_t            frameNb, nbStillImages;
41     ADMImage            *stillPicture;
42 
43     bool                updateTimingInfo(void);
44     void                cleanup(void);
45 
46 public:
47                         stillimage(ADM_coreVideoFilter *in, CONFcouple *conf);
48                         ~stillimage();
49     virtual const char  *getConfiguration(void); // Return current configuration as a human-readable string
50     virtual bool        getNextFrame(uint32_t *fn, ADMImage *image); // Get the next image
51     virtual bool        getCoupledConf(CONFcouple **couples); // Get the current filter configuration
52     virtual void        setCoupledConf(CONFcouple *couples);
53     virtual bool        goToTime(uint64_t usSeek);
54     virtual bool        getTimeRange(uint64_t *startTme, uint64_t *endTme); // Provide an updated time range for the next filter
55     virtual bool        configure(void); // Start graphical user interface
56 };
57 
58 DECLARE_VIDEO_FILTER(   stillimage,     // Class
59                         1,0,0,          // Version
60                         ADM_UI_ALL,     // UI
61                         VF_TRANSFORM,   // Category
62                         "stillimage",   // Internal name (must be unique!)
63                         QT_TRANSLATE_NOOP("stillimage", "Still Image"), // Display name
64                         QT_TRANSLATE_NOOP("stillimage", "Duplicate frames for a given duration.") // Description
65                     );
66 
67 /**
68     \fn getConfiguration
69 */
getConfiguration(void)70 const char *stillimage::getConfiguration(void)
71 {
72     static char buf[256];
73     snprintf(buf, 255, "Duplicate frame at %s for %.3f s",
74         ADM_us2plain(1000LL*params.start),
75         (double)params.duration/1000.);
76     return buf;
77 }
78 /**
79     \fn ctor
80 */
stillimage(ADM_coreVideoFilter * in,CONFcouple * setup)81 stillimage::stillimage( ADM_coreVideoFilter *in, CONFcouple *setup ) : ADM_coreVideoFilter(in, setup)
82 {
83     if(!setup || !ADM_paramLoad(setup, configuration_param, &params))
84     {
85         // Default values
86         params.start=0; // the first frame
87         params.duration=10000; // 10 seconds
88     }
89 
90     from=in->getAbsoluteStartTime();
91     timeIncrement=in->getInfo()->frameIncrement;
92     updateTimingInfo();
93     stillPicture=NULL;
94     frameNb=0;
95     nbStillImages=0;
96 }
97 
98 /**
99     \fn dtor
100 */
~stillimage()101 stillimage::~stillimage()
102 {
103     cleanup();
104 }
105 
106 /**
107     \fn cleanup
108 */
cleanup(void)109 void stillimage::cleanup(void)
110 {
111     if(stillPicture)
112         delete stillPicture;
113     stillPicture=NULL;
114 }
115 
116 /**
117     \fn getCoupledConf
118 */
getCoupledConf(CONFcouple ** couples)119 bool stillimage::getCoupledConf(CONFcouple **couples)
120 {
121     return ADM_paramSave(couples, configuration_param, &params);
122 }
123 
124 /**
125     \fn setCoupledConf
126 */
setCoupledConf(CONFcouple * couples)127 void stillimage::setCoupledConf(CONFcouple *couples)
128 {
129     ADM_paramLoad(couples, configuration_param, &params);
130 }
131 
132 /**
133     \fn goToTime
134 */
goToTime(uint64_t usSeek)135 bool stillimage::goToTime(uint64_t usSeek)
136 {
137     cleanup();
138     uint64_t time=usSeek;
139     if(time >= begin && time <= end)
140         time=begin;
141     else if(time > end)
142         time-=end-begin;
143     return previousFilter->goToTime(time);
144 }
145 
146 /**
147     \fn getTimeRange
148 */
getTimeRange(uint64_t * startTme,uint64_t * endTme)149 bool stillimage::getTimeRange(uint64_t *startTme, uint64_t *endTme)
150 {
151     *startTme=0;
152     *endTme=info.totalDuration;
153     return true;
154 }
155 
156 /**
157     \fn getNextFrame
158 */
getNextFrame(uint32_t * fn,ADMImage * image)159 bool stillimage::getNextFrame(uint32_t *fn, ADMImage *image)
160 {
161     // we have the image and are within range
162     if(stillPicture && stillPicture->Pts < end)
163     {
164         uint64_t pts=stillPicture->Pts;
165         pts+=timeIncrement;
166         stillPicture->Pts=pts;
167         // output our image instead of requesting a new frame from the previous filter
168         image->duplicate(stillPicture);
169         frameNb++;
170         *fn=frameNb;
171         nbStillImages++;
172         aprintf("[stillimage] stillPicture PTS = %s, frame %d\n",ADM_us2plain(pts),*fn);
173         return true;
174     }
175     // not in range, get a frame from the previous filter
176     if(!previousFilter->getNextFrame(fn,image))
177         return false;
178     uint64_t pts=image->Pts;
179     if(pts==ADM_NO_PTS || pts < begin)
180     {
181         *fn+=nbStillImages;
182         return true;
183     }
184     aprintf("[stillimage] original image PTS = %" PRIu64" ms\n",pts/1000);
185     // now in range, create our image
186     if(!stillPicture)
187     {
188         aprintf("[stillimage] creating stillPicture\n");
189         stillPicture=new ADMImageDefault(previousFilter->getInfo()->width, previousFilter->getInfo()->height);
190         stillPicture->duplicate(image);
191         frameNb=*fn;
192         return true;
193     }
194     // past the end, adjust the PTS and the frame count
195     pts+=end-begin;
196     image->Pts=pts;
197     *fn+=nbStillImages;
198     aprintf("[stillimage] final image PTS = %" PRIu64" ms, frame %d\n",pts/1000,*fn);
199 
200     return true;
201 }
202 
203 /**
204     \fn updateTimingInfo
205     \brief perform a sanity check and update info with the new totalDuration
206 */
updateTimingInfo(void)207 bool stillimage::updateTimingInfo(void)
208 {
209     uint64_t old=previousFilter->getInfo()->totalDuration;
210     if(1000LL*params.start + timeIncrement > old)
211     {
212         if(old > timeIncrement)
213             params.start=(uint32_t)((old-timeIncrement)/1000);
214         else
215             params.start=0;
216     }
217 
218     begin=1000LL*params.start;
219     end=begin+1000LL*params.duration;
220     if(from < begin)
221     {
222         begin-=from;
223         end-=from;
224     }else if(from < end)
225     {
226         begin=0;
227         end-=from;
228     }else
229     {
230         begin=end=0;
231     }
232 
233     info.totalDuration=old+end-begin;
234     return true;
235 }
236 
237 /**
238     \fn configure
239 */
configure(void)240 bool stillimage::configure(void)
241 {
242     uint32_t dur=(uint32_t)(previousFilter->getInfo()->totalDuration/1000LL);
243     uint32_t max9h=9*3600*1000;
244 
245     diaElemTimeStamp start(&params.start,QT_TRANSLATE_NOOP("stillimage","_Start time:"),0,dur);
246     diaElemTimeStamp duration(&params.duration,QT_TRANSLATE_NOOP("stillimage","_Duration:"),0,max9h);
247 
248     diaElem *elems[2]={&start,&duration};
249     bool r=diaFactoryRun(QT_TRANSLATE_NOOP("stillimage","Still Image"),2,elems);
250     updateTimingInfo();
251     return r;
252 }
253 
254 //EOF
255