]> git.sesse.net Git - kdenlive/blob - src/kthumb.cpp
got first audio frames, but
[kdenlive] / src / kthumb.cpp
1 /***************************************************************************
2                         krender.cpp  -  description
3                            -------------------
4   begin                : Fri Nov 22 2002
5   copyright            : (C) 2002 by Jason Wood
6   email                : jasonwood@blueyonder.co.uk
7   copyright            : (C) 2005 Lcio Fl�io Corr�  
8   email                : lucio.correa@gmail.com
9   copyright            : (C) Marco Gittler
10   email                : g.marco@freenet.de
11
12 ***************************************************************************/
13
14 /***************************************************************************
15  *                                                                         *
16  *   This program is free software; you can redistribute it and/or modify  *
17  *   it under the terms of the GNU General Public License as published by  *
18  *   the Free Software Foundation; either version 2 of the License, or     *
19  *   (at your option) any later version.                                   *
20  *                                                                         *
21  ***************************************************************************/
22
23 #include <qapplication.h>
24
25 #include <kio/netaccess.h>
26 #include <kdebug.h>
27 #include <klocale.h>
28 #include <kdenlivesettings.h>
29 #include <kfileitem.h>
30 #include <kmessagebox.h>
31
32 #include <mlt++/Mlt.h>
33
34 #include <qxml.h>
35 #include <qimage.h>
36
37 #include <QThread>
38 #include <QApplication>
39 #include <QCryptographicHash>
40
41
42 #include "renderer.h"
43 #include "kthumb.h"
44 #include "kdenlivesettings.h"
45
46 void MyThread::init(KUrl url, QString target, double frame, double frameLength, int frequency, int channels, int arrayWidth)
47     {
48         stop_me = false;
49         m_isWorking = false;
50         f.setFileName(target);
51         m_url = url;
52         m_frame = frame;
53         m_frameLength = frameLength;
54         m_frequency = frequency;
55         m_channels = channels;
56         m_arrayWidth = arrayWidth;
57
58     }
59
60     bool MyThread::isWorking()
61     {
62         return m_isWorking;
63     }
64
65     void MyThread::run()
66     {
67                 
68                  if (!f.open( QIODevice::WriteOnly )) {
69                         kDebug()<<"++++++++  ERROR WRITING TO FILE: "<<f.fileName()<<endl;
70                         kDebug()<<"++++++++  DISABLING AUDIO THUMBS"<<endl;
71                         //TODO KdenliveSettings::setAudiothumbnails(false);
72                         return;
73                 }
74                 m_isWorking = true;
75                 Mlt::Profile prof((char*) KdenliveSettings::current_profile().data());
76                 Mlt::Producer m_producer(prof, m_url.path().toAscii().data());
77                 
78
79                 /*TODO if (KdenliveSettings::normaliseaudiothumbs()) {
80                     Mlt::Filter m_convert("volume");
81                     m_convert.set("gain", "normalise");
82                     m_producer.attach(m_convert);
83                 }*/
84
85                 /*TODO if (qApp->mainWidget()) 
86                     QApplication::postEvent(qApp->mainWidget(), new ProgressEvent(-1, 10005));
87         */
88                 int last_val = 0;
89                 int val = 0;
90                 kDebug() << "for " << m_frame << " " << m_frameLength << " " << m_producer.is_valid();
91                 for (int z=(int) m_frame;z<(int) (m_frame+m_frameLength) && m_producer.is_valid();z++){
92                         kDebug() << "starting audithumb for frame " << z;
93                         
94                         if (stop_me) break;
95                         val=(int)((z-m_frame)/(m_frame+m_frameLength)*100.0);
96                         if (last_val!=val & val > 1){
97                                 //TODO QApplication::postEvent(qApp->mainWidget(), new ProgressEvent(val, 10005));
98                                 last_val=val;
99                         }
100                                 m_producer.seek( z );
101                                 Mlt::Frame *mlt_frame = m_producer.get_frame();
102                                 if ( mlt_frame->is_valid() )
103                                 {
104                                         double m_framesPerSecond = mlt_producer_get_fps( m_producer.get_producer() ); //mlt_frame->get_double( "fps" );
105                                         int m_samples = mlt_sample_calculator( m_framesPerSecond, m_frequency, mlt_frame_get_position(mlt_frame->get_frame()) );
106                                         mlt_audio_format m_audioFormat = mlt_audio_pcm;
107                                 
108                                         int16_t* m_pcm = mlt_frame->get_audio(m_audioFormat, m_frequency, m_channels, m_samples ); 
109
110                                         for (int c=0;c< m_channels;c++){
111                                                 QByteArray m_array;
112                                                 m_array.resize(m_arrayWidth);
113                                                 for (uint i = 0; i < m_array.size(); i++){
114                                                         m_array[i] =  qAbs((*( m_pcm + c + i * m_samples / m_array.size() ))>>8);
115                                                 }
116                                                 f.write(m_array);
117                                                 
118                                         }
119                                 } else{
120                                         f.write(QByteArray(m_arrayWidth,'\x00'));
121                                 }
122                                 if (mlt_frame)
123                                         delete mlt_frame;
124                 }
125                 f.close();
126                 m_isWorking = false;
127                 if (stop_me) {
128                     f.remove();
129                    //TODO  QApplication::postEvent(qApp->mainWidget(), new ProgressEvent(-1, 10005));
130                 }
131                 //TODO else QApplication::postEvent(qApp->mainWidget(), new ProgressEvent(0, 10005));
132     }
133
134
135 #define _S(a)           (a)>255 ? 255 : (a)<0 ? 0 : (a)
136 #define _R(y,u,v) (0x2568*(y)                          + 0x3343*(u)) /0x2000
137 #define _G(y,u,v) (0x2568*(y) - 0x0c92*(v) - 0x1a1e*(u)) /0x2000
138 #define _B(y,u,v) (0x2568*(y) + 0x40cf*(v))                                          /0x2000
139
140 KThumb::KThumb(KUrl url, int width, int height, QObject * parent, const char *name):QObject(parent), m_url(url), m_width(width), m_height(height)
141 {
142   kDebug()<<"+++++++++++  CREATING THMB PROD FOR: "<<url;
143   m_profile = new Mlt::Profile((char*) qstrdup(KdenliveSettings::current_profile().toUtf8()));
144 }
145
146 KThumb::~KThumb()
147 {
148     if (m_profile) delete m_profile;
149     if (thumbProducer.isRunning ()) thumbProducer.exit();
150 }
151
152
153 //static
154 QPixmap KThumb::getImage(KUrl url, int width, int height)
155 {
156     if (url.isEmpty()) return QPixmap();
157     QPixmap pix(width, height);
158   kDebug()<<"+++++++++++  GET THMB IMG FOR: "<<url;
159     char *tmp = Render::decodedString(url.path());
160     Mlt::Profile prof((char*) KdenliveSettings::current_profile().data());
161     Mlt::Producer m_producer(prof, tmp);
162     delete tmp;
163
164     if (m_producer.is_blank()) {
165         pix.fill(Qt::black);
166         return pix;
167     }
168     Mlt::Frame * m_frame;
169     mlt_image_format format = mlt_image_rgb24a;
170     Mlt::Filter m_convert(prof, "avcolour_space");
171     m_convert.set("forced", mlt_image_rgb24a);
172     m_producer.attach(m_convert);
173     //m_producer.seek(frame);
174     m_frame = m_producer.get_frame();
175     if (m_frame && m_frame->is_valid()) {
176       uint8_t *thumb = m_frame->get_image(format, width, height);
177       QImage image(thumb, width, height, QImage::Format_ARGB32);
178       if (!image.isNull()) {
179         pix = pix.fromImage(image);
180       }
181       else pix.fill(Qt::black);
182     }
183     if (m_frame) delete m_frame;
184     return pix;
185 }
186
187 void KThumb::extractImage(int frame, int frame2)
188 {
189     if (m_url.isEmpty()) return;
190     QPixmap pix(m_width, m_height);
191     char *tmp = Render::decodedString(m_url.path());
192     Mlt::Producer m_producer(*m_profile, tmp);
193     delete tmp;
194
195     if (m_producer.is_blank()) {
196         pix.fill(Qt::black);
197         emit thumbReady(frame, pix);
198         return;
199     }
200     Mlt::Frame * m_frame;
201     mlt_image_format format = mlt_image_rgb24a;
202     Mlt::Filter m_convert(*m_profile, "avcolour_space");
203     m_convert.set("forced", mlt_image_rgb24a);
204     m_producer.attach(m_convert);
205     if (frame != -1) {
206       m_producer.seek(frame);
207       m_frame = m_producer.get_frame();
208       if (m_frame && m_frame->is_valid()) {
209         uint8_t *thumb = m_frame->get_image(format, m_width, m_height);
210         QImage image(thumb, m_width, m_height, QImage::Format_ARGB32);
211         if (!image.isNull()) {
212           pix = pix.fromImage(image);
213         }
214         else pix.fill(Qt::black);
215       }
216       if (m_frame) delete m_frame;
217       emit thumbReady(frame, pix);
218     }
219     if (frame2 == -1) return;
220     m_producer.seek(frame2);
221     m_frame = m_producer.get_frame();
222     if (m_frame && m_frame->is_valid()) {
223       uint8_t *thumb = m_frame->get_image(format, m_width, m_height);
224       QImage image(thumb, m_width, m_height, QImage::Format_ARGB32);
225       if (!image.isNull()) {
226         pix = pix.fromImage(image);
227       }
228       else pix.fill(Qt::black);
229     }
230     if (m_frame) delete m_frame;
231     emit thumbReady(frame2, pix);
232
233 }
234 /*
235 void KThumb::getImage(KUrl url, int frame, int width, int height)
236 {
237     if (url.isEmpty()) return;
238     QPixmap image(width, height);
239     char *tmp = KRender::decodedString(url.path());
240     Mlt::Producer m_producer(tmp);
241     delete tmp;
242     image.fill(Qt::black);
243
244     if (m_producer.is_blank()) {
245         emit thumbReady(frame, image);
246         return;
247     }
248     Mlt::Filter m_convert("avcolour_space");
249     m_convert.set("forced", mlt_image_rgb24a);
250     m_producer.attach(m_convert);
251     m_producer.seek(frame);
252     Mlt::Frame * m_frame = m_producer.get_frame();
253     mlt_image_format format = mlt_image_rgb24a;
254     width = width - 2;
255     height = height - 2;
256     if (m_frame && m_frame->is_valid()) {
257         uint8_t *thumb = m_frame->get_image(format, width, height);
258         QImage tmpimage(thumb, width, height, 32, NULL, 0, QImage::IgnoreEndian);
259         if (!tmpimage.isNull()) bitBlt(&image, 1, 1, &tmpimage, 0, 0, width + 2, height + 2);
260     }
261     if (m_frame) delete m_frame;
262     emit thumbReady(frame, image);
263 }
264
265 void KThumb::getThumbs(KUrl url, int startframe, int endframe, int width, int height)
266 {
267     if (url.isEmpty()) return;
268     QPixmap image(width, height);
269     char *tmp = KRender::decodedString(url.path());
270     Mlt::Producer m_producer(tmp);
271     delete tmp;
272     image.fill(Qt::black);
273
274     if (m_producer.is_blank()) {
275         emit thumbReady(startframe, image);
276         emit thumbReady(endframe, image);
277         return;
278     }
279     Mlt::Filter m_convert("avcolour_space");
280     m_convert.set("forced", mlt_image_rgb24a);
281     m_producer.attach(m_convert);
282     m_producer.seek(startframe);
283     Mlt::Frame * m_frame = m_producer.get_frame();
284     mlt_image_format format = mlt_image_rgb24a;
285     width = width - 2;
286     height = height - 2;
287
288     if (m_frame && m_frame->is_valid()) {
289         uint8_t *thumb = m_frame->get_image(format, width, height);
290         QImage tmpimage(thumb, width, height, 32, NULL, 0, QImage::IgnoreEndian);
291         if (!tmpimage.isNull()) bitBlt(&image, 1, 1, &tmpimage, 0, 0, width - 2, height - 2);
292     }
293     if (m_frame) delete m_frame;
294     emit thumbReady(startframe, image);
295
296     image.fill(Qt::black);
297     m_producer.seek(endframe);
298     m_frame = m_producer.get_frame();
299
300     if (m_frame && m_frame->is_valid()) {
301         uint8_t *thumb = m_frame->get_image(format, width, height);
302         QImage tmpimage(thumb, width, height, 32, NULL, 0, QImage::IgnoreEndian);
303         if (!tmpimage.isNull()) bitBlt(&image, 1, 1, &tmpimage, 0, 0, width - 2, height - 2);
304     }
305     if (m_frame) delete m_frame;
306     emit thumbReady(endframe, image);
307 }
308 */
309 void KThumb::stopAudioThumbs()
310 {
311         if (thumbProducer.isRunning ()) thumbProducer.stop_me = true;
312 }
313
314
315 void KThumb::removeAudioThumb()
316 {
317         if (m_thumbFile.isEmpty()) return;
318         stopAudioThumbs();
319         QFile f(m_thumbFile);
320         f.remove();
321 }
322
323 void KThumb::getAudioThumbs(KUrl url, int channel, double frame, double frameLength, int arrayWidth){
324         
325         if ((thumbProducer.isRunning () && thumbProducer.isWorking()) || channel == 0) {
326             return;
327         }
328         
329         QMap <int, QMap <int, QByteArray> > storeIn;
330        //FIXME: Hardcoded!!! 
331         int m_frequency = 48000;
332         int m_channels = channel;
333         
334         m_thumbFile="/tmp/testfile";
335         /*FIXME WHY crash here ??????
336         if (m_url != url) {
337                 m_url = url;
338                 QCryptographicHash context(QCryptographicHash::Sha1);
339                 context.addData((KFileItem(m_url,"text/plain", S_IFREG).timeString() + m_url.fileName()).toAscii().data());
340                 
341                 m_thumbFile = KdenliveSettings::currenttmpfolder() + context.result().toHex() + ".thumb";
342                 
343         }*/
344         
345         QFile f(m_thumbFile);
346         if (f.open( QIODevice::ReadOnly )) {
347                 QByteArray channelarray = f.readAll();
348                 f.close();
349                 if (channelarray.size() != arrayWidth*(frame+frameLength)*m_channels) {
350                         kDebug()<<"--- BROKEN THUMB FOR: "<<m_url.fileName()<<" ---------------------- "<<endl;
351                         f.remove();
352                         return;
353                 }
354                 
355                 for (int z=(int) frame;z<(int) (frame+frameLength);z++) {
356                         for (int c=0;c< m_channels;c++){
357                                 QByteArray m_array;
358                                 m_array.resize(arrayWidth);
359                                 for (int i = 0; i < arrayWidth; i++)
360                                         m_array[i] = channelarray[z*arrayWidth*m_channels + c*arrayWidth + i];
361                                 storeIn[z][c] = m_array;
362                         }
363                 }
364                 emit audioThumbReady(storeIn);
365         }
366         else {
367                 if (thumbProducer.isRunning()) return;
368                 thumbProducer.init(m_url, m_thumbFile, frame, frameLength, m_frequency, m_channels, arrayWidth);
369                 thumbProducer.start(QThread::LowestPriority );
370         }
371 }
372
373
374