1 /***************************************************************************
2 mltdevicecapture.cpp - description
4 begin : Sun May 21 2011
5 copyright : (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org)
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 ***************************************************************************/
19 #include "mltdevicecapture.h"
20 #include "kdenlivesettings.h"
21 #include "definitions.h"
23 #include <mlt++/Mlt.h>
26 #include <KStandardDirs>
27 #include <KMessageBox>
29 #include <KTemporaryFile>
34 #include <QApplication>
45 static void consumer_gl_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
47 // detect if the producer has finished playing. Is there a better way to do it?
48 Mlt::Frame frame(frame_ptr);
49 self->showFrame(frame);
52 /*static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
54 Mlt::Frame frame(frame_ptr);
55 if (!frame.is_valid()) return;
56 self->gotCapturedFrame(frame);
59 static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
61 Mlt::Frame frame(frame_ptr);
62 if (!frame.is_valid()) return;
63 if (self->sendFrameForAnalysis && frame_ptr->convert_image) {
64 self->emitFrameUpdated(frame);
66 if (self->doCapture > 0) {
68 if (self->doCapture == 0) self->saveFrame(frame);
71 //TODO: connect record monitor to audio scopes
73 if (self->analyseAudio) {
74 self->showAudio(frame);
80 MltDeviceCapture::MltDeviceCapture(QString profile, VideoSurface *surface, QWidget *parent) :
81 AbstractRender(Kdenlive::recordMonitor, parent),
83 sendFrameForAnalysis(false),
84 processingImage(false),
88 m_showFrameEvent(NULL),
90 m_livePreview(KdenliveSettings::enable_recording_preview()),
91 m_winid((int) surface->winId())
93 m_captureDisplayWidget = surface;
94 analyseAudio = KdenliveSettings::monitor_audio();
95 if (profile.isEmpty()) profile = KdenliveSettings::current_profile();
96 buildConsumer(profile);
97 connect(this, SIGNAL(unblockPreview()), this, SLOT(slotPreparePreview()));
98 m_droppedFramesTimer.setSingleShot(false);
99 m_droppedFramesTimer.setInterval(1000);
100 connect(&m_droppedFramesTimer, SIGNAL(timeout()), this, SLOT(slotCheckDroppedFrames()));
103 MltDeviceCapture::~MltDeviceCapture()
105 if (m_mltConsumer) delete m_mltConsumer;
106 if (m_mltProducer) delete m_mltProducer;
107 if (m_mltProfile) delete m_mltProfile;
110 void MltDeviceCapture::buildConsumer(const QString &profileName)
112 if (!profileName.isEmpty()) m_activeProfile = profileName;
114 if (m_mltProfile) delete m_mltProfile;
116 char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
117 setenv("MLT_PROFILE", tmp, 1);
118 m_mltProfile = new Mlt::Profile(tmp);
119 m_mltProfile->set_explicit(true);
122 QString videoDriver = KdenliveSettings::videodrivername();
123 if (!videoDriver.isEmpty()) {
124 if (videoDriver == "x11_noaccel") {
125 setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
128 unsetenv("SDL_VIDEO_YUV_HWACCEL");
131 setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
136 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_audio");
137 m_mltConsumer->set("preview_off", 1);
138 m_mltConsumer->set("preview_format", mlt_image_rgb24);
139 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
141 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
142 m_mltConsumer->set("window_id", m_winid);
143 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
145 //m_mltConsumer->set("resize", 1);
146 //m_mltConsumer->set("terminate_on_pause", 1);
147 m_mltConsumer->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
148 //m_mltConsumer->set("rescale", "nearest");
150 QString audioDevice = KdenliveSettings::audiodevicename();
151 if (!audioDevice.isEmpty())
152 m_mltConsumer->set("audio_device", audioDevice.toUtf8().constData());
154 if (!videoDriver.isEmpty())
155 m_mltConsumer->set("video_driver", videoDriver.toUtf8().constData());
157 QString audioDriver = KdenliveSettings::audiodrivername();
159 if (!audioDriver.isEmpty())
160 m_mltConsumer->set("audio_driver", audioDriver.toUtf8().constData());
162 //m_mltConsumer->set("progressive", 0);
163 //m_mltConsumer->set("buffer", 1);
164 //m_mltConsumer->set("real_time", 0);
167 void MltDeviceCapture::pause()
170 m_mltConsumer->set("refresh", 0);
171 //m_mltProducer->set_speed(0.0);
172 m_mltConsumer->purge();
176 void MltDeviceCapture::stop()
178 m_droppedFramesTimer.stop();
179 bool isPlaylist = false;
180 //disconnect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
181 //m_captureDisplayWidget->stop();
183 if (m_showFrameEvent) delete m_showFrameEvent;
184 m_showFrameEvent = NULL;
187 m_mltConsumer->set("refresh", 0);
188 m_mltConsumer->purge();
189 m_mltConsumer->stop();
190 //if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
193 QList <Mlt::Producer *> prods;
194 Mlt::Service service(m_mltProducer->parent().get_service());
195 mlt_service_lock(service.get_service());
196 if (service.type() == tractor_type) {
198 Mlt::Tractor tractor(service);
199 mlt_tractor_close(tractor.get_tractor());
200 Mlt::Field *field = tractor.field();
201 mlt_service nextservice = mlt_service_get_producer(service.get_service());
202 mlt_service nextservicetodisconnect;
203 mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
204 QString mlt_type = mlt_properties_get(properties, "mlt_type");
205 QString resource = mlt_properties_get(properties, "mlt_service");
206 // Delete all transitions
207 while (mlt_type == "transition") {
208 nextservicetodisconnect = nextservice;
209 nextservice = mlt_service_producer(nextservice);
210 mlt_field_disconnect_service(field->get_field(), nextservicetodisconnect);
211 if (nextservice == NULL) break;
212 properties = MLT_SERVICE_PROPERTIES(nextservice);
213 mlt_type = mlt_properties_get(properties, "mlt_type");
214 resource = mlt_properties_get(properties, "mlt_service");
219 mlt_service_unlock(service.get_service());
220 delete m_mltProducer;
221 m_mltProducer = NULL;
223 // For some reason, the consumer seems to be deleted by previous stuff when in playlist mode
224 if (!isPlaylist && m_mltConsumer) delete m_mltConsumer;
225 m_mltConsumer = NULL;
229 void MltDeviceCapture::slotDoRefresh()
231 QMutexLocker locker(&m_mutex);
235 if (m_mltConsumer->is_stopped()) m_mltConsumer->start();
236 m_mltConsumer->purge();
237 m_mltConsumer->set("refresh", 1);
242 void MltDeviceCapture::emitFrameUpdated(Mlt::Frame& frame)
245 //TEST: is it better to convert the frame in a thread outside of MLT??
246 if (processingImage) return;
247 mlt_image_format format = (mlt_image_format) frame.get_int("format"); //mlt_image_rgb24;
248 int width = frame.get_int("width");
249 int height = frame.get_int("height");
250 unsigned char *buffer = (unsigned char *) frame.get_data("image");
251 if (format == mlt_image_yuv422) {
252 QtConcurrent::run(this, &MltDeviceCapture::uyvy2rgb, (unsigned char *) buffer, width, height);
256 mlt_image_format format = mlt_image_rgb24;
259 const uchar* image = frame.get_image(format, width, height);
260 QImage qimage(width, height, QImage::Format_RGB888);
261 //QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
262 memcpy(qimage.bits(), image, width * height * 3);
263 emit frameUpdated(qimage);
266 void MltDeviceCapture::showFrame(Mlt::Frame& frame)
268 mlt_image_format format = mlt_image_rgb24;
271 const uchar* image = frame.get_image(format, width, height);
272 QImage qimage(width, height, QImage::Format_RGB888);
273 memcpy(qimage.scanLine(0), image, width * height * 3);
274 emit showImageSignal(qimage);
276 if (sendFrameForAnalysis && frame.get_frame()->convert_image) {
277 emit frameUpdated(qimage.rgbSwapped());
281 void MltDeviceCapture::showAudio(Mlt::Frame& frame)
283 if (!frame.is_valid() || frame.get_int("test_audio") != 0) {
286 mlt_audio_format audio_format = mlt_audio_s16;
288 int num_channels = 0;
290 int16_t* data = (int16_t*)frame.get_audio(audio_format, freq, num_channels, samples);
296 // Data format: [ c00 c10 c01 c11 c02 c12 c03 c13 ... c0{samples-1} c1{samples-1} for 2 channels.
297 // So the vector is of size samples*channels.
298 QVector<int16_t> sampleVector(samples*num_channels);
299 memcpy(sampleVector.data(), data, samples*num_channels*sizeof(int16_t));
301 emit audioSamplesSignal(sampleVector, freq, num_channels, samples);
305 bool MltDeviceCapture::slotStartPreview(const QString &producer, bool xmlFormat)
307 if (m_mltConsumer == NULL) {
310 char *tmp = qstrdup(producer.toUtf8().constData());
311 if (xmlFormat) m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", tmp);
312 else m_mltProducer = new Mlt::Producer(*m_mltProfile, tmp);
315 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) {
317 delete m_mltProducer;
318 m_mltProducer = NULL;
320 kDebug()<<"//// ERROR CREATRING PROD";
323 m_mltConsumer->connect(*m_mltProducer);
324 if (m_mltConsumer->start() == -1) {
325 delete m_mltConsumer;
326 m_mltConsumer = NULL;
329 m_droppedFramesTimer.start();
330 //connect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
334 void MltDeviceCapture::slotCheckDroppedFrames()
337 int dropped = m_mltProducer->get_int("dropped");
338 if (dropped > m_droppedFrames) {
339 m_droppedFrames = dropped;
340 emit droppedFrames(m_droppedFrames);
345 void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame)
348 int dropped = m_mltProducer->get_int("dropped");
349 if (dropped > m_droppedFrames) {
350 m_droppedFrames = dropped;
351 emit droppedFrames(m_droppedFrames);
355 if (!m_livePreview) return;
356 //if (m_livePreview == 0 && (m_frameCount % 10 > 0)) return;
357 mlt_image_format format = mlt_image_rgb24;
360 uint8_t *data = frame.get_image(format, width, height, 0);
361 //QImage image(width, height, QImage::Format_RGB888);
362 //memcpy(image.bits(), data, width * height * 3);
363 QImage image((uchar *)data, width, height, QImage::Format_RGB888);
365 //m_captureDisplayWidget->setImage(image);
367 //TEST: is it better to process frame conversion ouside MLT???
369 if (!m_livePreview || processingImage) return;
371 mlt_image_format format = (mlt_image_format) frame.get_int("format"); //mlt_image_rgb24a;
372 int width = frame.get_int("width");
373 int height = frame.get_int("height");
374 unsigned char *buffer = (unsigned char *) frame.get_data("image");
375 //unsigned char *buffer = frame.get_image(format, width, height);
376 //convert from uyvy422 to rgba
377 if (format == mlt_image_yuv422) {
378 QtConcurrent::run(this, &MltDeviceCapture::uyvy2rgb, (unsigned char *) buffer, width, height);
379 //CaptureHandler::uyvy2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight());
383 void MltDeviceCapture::saveFrame(Mlt::Frame& frame)
385 mlt_image_format format = mlt_image_rgb24;
388 const uchar* image = frame.get_image(format, width, height);
389 QImage qimage(width, height, QImage::Format_RGB888);
390 memcpy(qimage.bits(), image, width * height * 3);
393 Mlt::Service service(m_mltProducer->parent().get_service());
394 Mlt::Tractor tractor(service);
395 Mlt::Producer trackProducer(tractor.track(0));
396 trackProducer.set("hide", 0);
398 qimage.save(m_capturePath);
399 emit frameSaved(m_capturePath);
400 m_capturePath.clear();
403 void MltDeviceCapture::captureFrame(const QString &path)
405 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
407 // Hide overlay track before doing the capture
408 Mlt::Service service(m_mltProducer->parent().get_service());
409 Mlt::Tractor tractor(service);
410 Mlt::Producer trackProducer(tractor.track(0));
411 mlt_service_lock(service.get_service());
412 trackProducer.set("hide", 1);
413 m_mltConsumer->purge();
414 mlt_service_unlock(service.get_service());
415 m_capturePath = path;
416 // Wait for 5 frames before capture to make sure overlay is gone
420 bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist, bool livePreview, bool xmlPlaylist)
423 m_livePreview = livePreview;
426 if (m_mltProfile) delete m_mltProfile;
427 char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
428 m_mltProfile = new Mlt::Profile(tmp);
430 //m_mltProfile->get_profile()->is_explicit = 1;
433 /*kDebug()<<"-- CREATING CAP: "<<params<<", PATH: "<<path;
434 tmp = qstrdup(QString("avformat:" + path).toUtf8().constData());
435 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, tmp);
436 m_mltConsumer->set("real_time", -KdenliveSettings::mltthreads());
439 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "multi");
440 if (m_mltConsumer == NULL || !m_mltConsumer->is_valid()) {
442 delete m_mltConsumer;
443 m_mltConsumer = NULL;
448 m_winid = (int) m_captureDisplayWidget->winId();
450 // Create multi consumer setup
451 Mlt::Properties *renderProps = new Mlt::Properties;
452 renderProps->set("mlt_service", "avformat");
453 renderProps->set("target", path.toUtf8().constData());
454 renderProps->set("real_time", -KdenliveSettings::mltthreads());
455 //renderProps->set("terminate_on_pause", 0);
456 renderProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
459 QStringList paramList = params.split(' ', QString::SkipEmptyParts);
461 for (int i = 0; i < paramList.count(); ++i) {
462 tmp = qstrdup(paramList.at(i).section('=', 0, 0).toUtf8().constData());
463 QString value = paramList.at(i).section('=', 1, 1);
464 if (value == "%threads") value = QString::number(QThread::idealThreadCount());
465 tmp2 = qstrdup(value.toUtf8().constData());
466 renderProps->set(tmp, tmp2);
470 mlt_properties consumerProperties = m_mltConsumer->get_properties();
471 mlt_properties_set_data(consumerProperties, "0", renderProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
475 // user wants live preview
476 Mlt::Properties *previewProps = new Mlt::Properties;
477 QString videoDriver = KdenliveSettings::videodrivername();
478 if (!videoDriver.isEmpty()) {
479 if (videoDriver == "x11_noaccel") {
480 setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
483 unsetenv("SDL_VIDEO_YUV_HWACCEL");
486 setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
490 previewProps->set("mlt_service", "sdl_audio");
491 previewProps->set("preview_off", 1);
492 previewProps->set("preview_format", mlt_image_rgb24);
493 previewProps->set("terminate_on_pause", 0);
494 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
496 previewProps->set("mlt_service", "sdl_preview");
497 previewProps->set("window_id", m_winid);
498 previewProps->set("terminate_on_pause", 0);
499 //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
501 //m_mltConsumer->set("resize", 1);
502 previewProps->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
503 QString audioDevice = KdenliveSettings::audiodevicename();
504 if (!audioDevice.isEmpty())
505 previewProps->set("audio_device", audioDevice.toUtf8().constData());
507 if (!videoDriver.isEmpty())
508 previewProps->set("video_driver", videoDriver.toUtf8().constData());
510 QString audioDriver = KdenliveSettings::audiodrivername();
512 if (!audioDriver.isEmpty())
513 previewProps->set("audio_driver", audioDriver.toUtf8().constData());
515 previewProps->set("real_time", "0");
516 previewProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
517 mlt_properties_set_data(consumerProperties, "1", previewProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
518 //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-render", this, (mlt_listener) rec_consumer_frame_show);
525 // create an xml producer
526 m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", playlist.toUtf8().constData());
529 // create a producer based on mltproducer parameter
530 m_mltProducer = new Mlt::Producer(*m_mltProfile, playlist.toUtf8().constData());
533 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) {
534 kDebug()<<"//// ERROR CREATRING PROD";
536 delete m_mltConsumer;
537 m_mltConsumer = NULL;
540 delete m_mltProducer;
541 m_mltProducer = NULL;
546 m_mltConsumer->connect(*m_mltProducer);
547 if (m_mltConsumer->start() == -1) {
548 if (m_showFrameEvent) delete m_showFrameEvent;
549 m_showFrameEvent = NULL;
550 delete m_mltConsumer;
551 m_mltConsumer = NULL;
554 m_droppedFramesTimer.start();
559 void MltDeviceCapture::setOverlay(const QString &path)
561 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
562 Mlt::Producer parentProd(m_mltProducer->parent());
563 if (parentProd.get_producer() == NULL) {
564 kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////";
568 Mlt::Service service(parentProd.get_service());
569 if (service.type() != tractor_type) {
570 kWarning() << "// TRACTOR PROBLEM";
573 Mlt::Tractor tractor(service);
574 if ( tractor.count() < 2) {
575 kWarning() << "// TRACTOR PROBLEM";
578 mlt_service_lock(service.get_service());
579 Mlt::Producer trackProducer(tractor.track(0));
580 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
582 trackPlaylist.remove(0);
583 if (path.isEmpty()) {
584 mlt_service_unlock(service.get_service());
589 char *tmp = qstrdup(path.toUtf8().constData());
590 Mlt::Producer *clip = new Mlt::Producer (*m_mltProfile, "loader", tmp);
592 clip->set_in_and_out(0, 99999);
593 trackPlaylist.insert_at(0, clip, 1);
596 mlt_service serv = m_mltProducer->parent().get_service();
597 mlt_service nextservice = mlt_service_get_producer(serv);
598 mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
599 QString mlt_type = mlt_properties_get(properties, "mlt_type");
600 if (mlt_type != "transition") {
601 // transition does not exist, add it
602 Mlt::Field *field = tractor.field();
603 Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, "composite");
604 transition->set_in_and_out(0, 0);
605 transition->set("geometry", "0/0:100%x100%:70");
606 transition->set("fill", 1);
607 transition->set("operator", "and");
608 transition->set("a_track", 0);
609 transition->set("b_track", 1);
610 field->plant_transition(*transition, 0, 1);
612 mlt_service_unlock(service.get_service());
616 void MltDeviceCapture::setOverlayEffect(const QString &tag, QStringList parameters)
618 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
619 Mlt::Service service(m_mltProducer->parent().get_service());
620 Mlt::Tractor tractor(service);
621 Mlt::Producer trackProducer(tractor.track(0));
622 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
623 Mlt::Service trackService(trackProducer.get_service());
625 mlt_service_lock(service.get_service());
627 // delete previous effects
629 filter = trackService.filter(0);
630 if (filter && !tag.isEmpty()) {
631 QString currentService = filter->get("mlt_service");
632 if (currentService == tag) {
633 // Effect is already there
634 mlt_service_unlock(service.get_service());
639 trackService.detach(*filter);
641 filter = trackService.filter(0);
645 mlt_service_unlock(service.get_service());
649 char *tmp = qstrdup(tag.toUtf8().constData());
650 filter = new Mlt::Filter(*m_mltProfile, tmp);
652 if (filter && filter->is_valid()) {
653 for (int j = 0; j < parameters.count(); j++) {
654 filter->set(parameters.at(j).section('=', 0, 0).toUtf8().constData(), parameters.at(j).section('=', 1, 1).toUtf8().constData());
656 trackService.attach(*filter);
658 mlt_service_unlock(service.get_service());
661 void MltDeviceCapture::mirror(bool activate)
663 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
664 Mlt::Service service(m_mltProducer->parent().get_service());
665 Mlt::Tractor tractor(service);
666 Mlt::Producer trackProducer(tractor.track(1));
667 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
668 Mlt::Service trackService(trackProducer.get_service());
670 mlt_service_lock(service.get_service());
672 // delete previous effects
674 filter = trackService.filter(0);
676 trackService.detach(*filter);
678 filter = trackService.filter(0);
682 mlt_service_unlock(service.get_service());
686 filter = new Mlt::Filter(*m_mltProfile, "mirror");
687 if (filter && filter->is_valid()) {
688 filter->set("mirror", "flip");
689 trackService.attach(*filter);
691 mlt_service_unlock(service.get_service());
694 void MltDeviceCapture::uyvy2rgb(unsigned char *yuv_buffer, int width, int height)
696 processingImage = true;
697 QImage image(width, height, QImage::Format_RGB888);
698 unsigned char *rgb_buffer = image.bits();
703 int rgb_ptr, y_ptr, t;
705 len = width * height / 2;
710 for (t = 0; t < len; t++) {
713 Y = yuv_buffer[y_ptr];
714 U = yuv_buffer[y_ptr+1];
715 Y2 = yuv_buffer[y_ptr+2];
716 V = yuv_buffer[y_ptr+3];
719 r = ((298 * (Y - 16) + 409 * (V - 128) + 128) >> 8);
721 g = ((298 * (Y - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8);
723 b = ((298 * (Y - 16) + 516 * (U - 128) + 128) >> 8);
725 if (r > 255) r = 255;
726 if (g > 255) g = 255;
727 if (b > 255) b = 255;
733 rgb_buffer[rgb_ptr] = r;
734 rgb_buffer[rgb_ptr+1] = g;
735 rgb_buffer[rgb_ptr+2] = b;
739 r = ((298 * (Y2 - 16) + 409 * (V - 128) + 128) >> 8);
741 g = ((298 * (Y2 - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8);
743 b = ((298 * (Y2 - 16) + 516 * (U - 128) + 128) >> 8);
745 if (r > 255) r = 255;
746 if (g > 255) g = 255;
747 if (b > 255) b = 255;
753 rgb_buffer[rgb_ptr] = r;
754 rgb_buffer[rgb_ptr+1] = g;
755 rgb_buffer[rgb_ptr+2] = b;
758 //emit imageReady(image);
759 //m_captureDisplayWidget->setImage(image);
760 emit unblockPreview();
761 //processingImage = false;
764 void MltDeviceCapture::slotPreparePreview()
766 QTimer::singleShot(1000, this, SLOT(slotAllowPreview()));
769 void MltDeviceCapture::slotAllowPreview()
771 processingImage = false;
776 #include "mltdevicecapture.moc"