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"
22 #include "widgets/videosurface.h"
24 #include <mlt++/Mlt.h>
27 #include <KStandardDirs>
28 #include <KMessageBox>
29 #include <KLocalizedString>
30 #include <KTemporaryFile>
35 #include <QApplication>
46 static void consumer_gl_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
48 // detect if the producer has finished playing. Is there a better way to do it?
49 Mlt::Frame frame(frame_ptr);
50 self->showFrame(frame);
53 /*static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
55 Mlt::Frame frame(frame_ptr);
56 if (!frame.is_valid()) return;
57 self->gotCapturedFrame(frame);
60 static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
62 Mlt::Frame frame(frame_ptr);
63 if (!frame.is_valid()) return;
64 if (self->sendFrameForAnalysis && frame_ptr->convert_image) {
65 self->emitFrameUpdated(frame);
67 if (self->doCapture > 0) {
69 if (self->doCapture == 0) self->saveFrame(frame);
72 //TODO: connect record monitor to audio scopes
74 if (self->analyseAudio) {
75 self->showAudio(frame);
81 MltDeviceCapture::MltDeviceCapture(QString profile, VideoSurface *surface, QWidget *parent) :
82 AbstractRender(Kdenlive::RecordMonitor, parent),
84 sendFrameForAnalysis(false),
85 processingImage(false),
89 m_showFrameEvent(NULL),
91 m_livePreview(KdenliveSettings::enable_recording_preview()),
92 m_winid((int) surface->winId())
94 m_captureDisplayWidget = surface;
95 analyseAudio = KdenliveSettings::monitor_audio();
96 if (profile.isEmpty())
97 profile = KdenliveSettings::current_profile();
98 buildConsumer(profile);
99 connect(this, SIGNAL(unblockPreview()), this, SLOT(slotPreparePreview()));
100 m_droppedFramesTimer.setSingleShot(false);
101 m_droppedFramesTimer.setInterval(1000);
102 connect(&m_droppedFramesTimer, SIGNAL(timeout()), this, SLOT(slotCheckDroppedFrames()));
105 MltDeviceCapture::~MltDeviceCapture()
107 if (m_mltConsumer) delete m_mltConsumer;
108 if (m_mltProducer) delete m_mltProducer;
109 if (m_mltProfile) delete m_mltProfile;
112 void MltDeviceCapture::buildConsumer(const QString &profileName)
114 if (!profileName.isEmpty()) m_activeProfile = profileName;
116 if (m_mltProfile) delete m_mltProfile;
118 char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
119 setenv("MLT_PROFILE", tmp, 1);
120 m_mltProfile = new Mlt::Profile(tmp);
121 m_mltProfile->set_explicit(true);
124 QString videoDriver = KdenliveSettings::videodrivername();
125 if (!videoDriver.isEmpty()) {
126 if (videoDriver == "x11_noaccel") {
127 setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
130 unsetenv("SDL_VIDEO_YUV_HWACCEL");
133 setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
138 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_audio");
139 m_mltConsumer->set("preview_off", 1);
140 m_mltConsumer->set("preview_format", mlt_image_rgb24);
141 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
143 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
144 m_mltConsumer->set("window_id", m_winid);
145 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
147 //m_mltConsumer->set("resize", 1);
148 //m_mltConsumer->set("terminate_on_pause", 1);
149 m_mltConsumer->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
150 //m_mltConsumer->set("rescale", "nearest");
152 QString audioDevice = KdenliveSettings::audiodevicename();
153 if (!audioDevice.isEmpty())
154 m_mltConsumer->set("audio_device", audioDevice.toUtf8().constData());
156 if (!videoDriver.isEmpty())
157 m_mltConsumer->set("video_driver", videoDriver.toUtf8().constData());
159 QString audioDriver = KdenliveSettings::audiodrivername();
161 if (!audioDriver.isEmpty())
162 m_mltConsumer->set("audio_driver", audioDriver.toUtf8().constData());
164 //m_mltConsumer->set("progressive", 0);
165 //m_mltConsumer->set("buffer", 1);
166 //m_mltConsumer->set("real_time", 0);
169 void MltDeviceCapture::pause()
172 m_mltConsumer->set("refresh", 0);
173 //m_mltProducer->set_speed(0.0);
174 m_mltConsumer->purge();
178 void MltDeviceCapture::stop()
180 m_droppedFramesTimer.stop();
181 bool isPlaylist = false;
182 //disconnect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
183 //m_captureDisplayWidget->stop();
185 if (m_showFrameEvent) delete m_showFrameEvent;
186 m_showFrameEvent = NULL;
189 m_mltConsumer->set("refresh", 0);
190 m_mltConsumer->purge();
191 m_mltConsumer->stop();
192 //if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
195 QList <Mlt::Producer *> prods;
196 Mlt::Service service(m_mltProducer->parent().get_service());
197 mlt_service_lock(service.get_service());
198 if (service.type() == tractor_type) {
200 Mlt::Tractor tractor(service);
201 mlt_tractor_close(tractor.get_tractor());
202 Mlt::Field *field = tractor.field();
203 mlt_service nextservice = mlt_service_get_producer(service.get_service());
204 mlt_service nextservicetodisconnect;
205 mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
206 QString mlt_type = mlt_properties_get(properties, "mlt_type");
207 QString resource = mlt_properties_get(properties, "mlt_service");
208 // Delete all transitions
209 while (mlt_type == "transition") {
210 nextservicetodisconnect = nextservice;
211 nextservice = mlt_service_producer(nextservice);
212 mlt_field_disconnect_service(field->get_field(), nextservicetodisconnect);
213 if (nextservice == NULL) break;
214 properties = MLT_SERVICE_PROPERTIES(nextservice);
215 mlt_type = mlt_properties_get(properties, "mlt_type");
216 resource = mlt_properties_get(properties, "mlt_service");
221 mlt_service_unlock(service.get_service());
222 delete m_mltProducer;
223 m_mltProducer = NULL;
225 // For some reason, the consumer seems to be deleted by previous stuff when in playlist mode
226 if (!isPlaylist && m_mltConsumer) delete m_mltConsumer;
227 m_mltConsumer = NULL;
231 void MltDeviceCapture::slotDoRefresh()
233 QMutexLocker locker(&m_mutex);
237 if (m_mltConsumer->is_stopped()) m_mltConsumer->start();
238 m_mltConsumer->purge();
239 m_mltConsumer->set("refresh", 1);
244 void MltDeviceCapture::emitFrameUpdated(Mlt::Frame& frame)
247 //TEST: is it better to convert the frame in a thread outside of MLT??
248 if (processingImage) return;
249 mlt_image_format format = (mlt_image_format) frame.get_int("format"); //mlt_image_rgb24;
250 int width = frame.get_int("width");
251 int height = frame.get_int("height");
252 unsigned char *buffer = (unsigned char *) frame.get_data("image");
253 if (format == mlt_image_yuv422) {
254 QtConcurrent::run(this, &MltDeviceCapture::uyvy2rgb, (unsigned char *) buffer, width, height);
258 mlt_image_format format = mlt_image_rgb24;
261 const uchar* image = frame.get_image(format, width, height);
262 QImage qimage(width, height, QImage::Format_RGB888);
263 //QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
264 memcpy(qimage.bits(), image, width * height * 3);
265 emit frameUpdated(qimage);
268 void MltDeviceCapture::showFrame(Mlt::Frame& frame)
270 mlt_image_format format = mlt_image_rgb24;
273 const uchar* image = frame.get_image(format, width, height);
274 QImage qimage(width, height, QImage::Format_RGB888);
275 memcpy(qimage.scanLine(0), image, width * height * 3);
276 emit showImageSignal(qimage);
278 if (sendFrameForAnalysis && frame.get_frame()->convert_image) {
279 emit frameUpdated(qimage.rgbSwapped());
283 void MltDeviceCapture::showAudio(Mlt::Frame& frame)
285 if (!frame.is_valid() || frame.get_int("test_audio") != 0) {
288 mlt_audio_format audio_format = mlt_audio_s16;
290 int num_channels = 0;
292 int16_t* data = (int16_t*)frame.get_audio(audio_format, freq, num_channels, samples);
298 // Data format: [ c00 c10 c01 c11 c02 c12 c03 c13 ... c0{samples-1} c1{samples-1} for 2 channels.
299 // So the vector is of size samples*channels.
300 QVector<int16_t> sampleVector(samples*num_channels);
301 memcpy(sampleVector.data(), data, samples*num_channels*sizeof(int16_t));
303 emit audioSamplesSignal(sampleVector, freq, num_channels, samples);
307 bool MltDeviceCapture::slotStartPreview(const QString &producer, bool xmlFormat)
309 if (m_mltConsumer == NULL) {
312 char *tmp = qstrdup(producer.toUtf8().constData());
313 if (xmlFormat) m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", tmp);
314 else m_mltProducer = new Mlt::Producer(*m_mltProfile, tmp);
317 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) {
319 delete m_mltProducer;
320 m_mltProducer = NULL;
322 kDebug()<<"//// ERROR CREATRING PROD";
325 m_mltConsumer->connect(*m_mltProducer);
326 if (m_mltConsumer->start() == -1) {
327 delete m_mltConsumer;
328 m_mltConsumer = NULL;
331 m_droppedFramesTimer.start();
332 //connect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
336 void MltDeviceCapture::slotCheckDroppedFrames()
339 int dropped = m_mltProducer->get_int("dropped");
340 if (dropped > m_droppedFrames) {
341 m_droppedFrames = dropped;
342 emit droppedFrames(m_droppedFrames);
347 void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame)
350 int dropped = m_mltProducer->get_int("dropped");
351 if (dropped > m_droppedFrames) {
352 m_droppedFrames = dropped;
353 emit droppedFrames(m_droppedFrames);
357 if (!m_livePreview) return;
358 //if (m_livePreview == 0 && (m_frameCount % 10 > 0)) return;
359 mlt_image_format format = mlt_image_rgb24;
362 uint8_t *data = frame.get_image(format, width, height, 0);
363 //QImage image(width, height, QImage::Format_RGB888);
364 //memcpy(image.bits(), data, width * height * 3);
365 QImage image((uchar *)data, width, height, QImage::Format_RGB888);
367 //m_captureDisplayWidget->setImage(image);
369 //TEST: is it better to process frame conversion ouside MLT???
371 if (!m_livePreview || processingImage) return;
373 mlt_image_format format = (mlt_image_format) frame.get_int("format"); //mlt_image_rgb24a;
374 int width = frame.get_int("width");
375 int height = frame.get_int("height");
376 unsigned char *buffer = (unsigned char *) frame.get_data("image");
377 //unsigned char *buffer = frame.get_image(format, width, height);
378 //convert from uyvy422 to rgba
379 if (format == mlt_image_yuv422) {
380 QtConcurrent::run(this, &MltDeviceCapture::uyvy2rgb, (unsigned char *) buffer, width, height);
381 //CaptureHandler::uyvy2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight());
385 void MltDeviceCapture::saveFrame(Mlt::Frame& frame)
387 mlt_image_format format = mlt_image_rgb24;
390 const uchar* image = frame.get_image(format, width, height);
391 QImage qimage(width, height, QImage::Format_RGB888);
392 memcpy(qimage.bits(), image, width * height * 3);
395 Mlt::Service service(m_mltProducer->parent().get_service());
396 Mlt::Tractor tractor(service);
397 Mlt::Producer trackProducer(tractor.track(0));
398 trackProducer.set("hide", 0);
400 qimage.save(m_capturePath);
401 emit frameSaved(m_capturePath);
402 m_capturePath.clear();
405 void MltDeviceCapture::captureFrame(const QString &path)
407 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
409 // Hide overlay track before doing the capture
410 Mlt::Service service(m_mltProducer->parent().get_service());
411 Mlt::Tractor tractor(service);
412 Mlt::Producer trackProducer(tractor.track(0));
413 mlt_service_lock(service.get_service());
414 trackProducer.set("hide", 1);
415 m_mltConsumer->purge();
416 mlt_service_unlock(service.get_service());
417 m_capturePath = path;
418 // Wait for 5 frames before capture to make sure overlay is gone
422 bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist, bool livePreview, bool xmlPlaylist)
425 m_livePreview = livePreview;
428 if (m_mltProfile) delete m_mltProfile;
429 char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
430 m_mltProfile = new Mlt::Profile(tmp);
432 //m_mltProfile->get_profile()->is_explicit = 1;
435 /*kDebug()<<"-- CREATING CAP: "<<params<<", PATH: "<<path;
436 tmp = qstrdup(QString("avformat:" + path).toUtf8().constData());
437 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, tmp);
438 m_mltConsumer->set("real_time", -KdenliveSettings::mltthreads());
441 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "multi");
442 if (m_mltConsumer == NULL || !m_mltConsumer->is_valid()) {
444 delete m_mltConsumer;
445 m_mltConsumer = NULL;
450 m_winid = (int) m_captureDisplayWidget->winId();
452 // Create multi consumer setup
453 Mlt::Properties *renderProps = new Mlt::Properties;
454 renderProps->set("mlt_service", "avformat");
455 renderProps->set("target", path.toUtf8().constData());
456 renderProps->set("real_time", -KdenliveSettings::mltthreads());
457 //renderProps->set("terminate_on_pause", 0);
458 renderProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
461 QStringList paramList = params.split(' ', QString::SkipEmptyParts);
463 for (int i = 0; i < paramList.count(); ++i) {
464 tmp = qstrdup(paramList.at(i).section('=', 0, 0).toUtf8().constData());
465 QString value = paramList.at(i).section('=', 1, 1);
466 if (value == "%threads") value = QString::number(QThread::idealThreadCount());
467 tmp2 = qstrdup(value.toUtf8().constData());
468 renderProps->set(tmp, tmp2);
472 mlt_properties consumerProperties = m_mltConsumer->get_properties();
473 mlt_properties_set_data(consumerProperties, "0", renderProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
477 // user wants live preview
478 Mlt::Properties *previewProps = new Mlt::Properties;
479 QString videoDriver = KdenliveSettings::videodrivername();
480 if (!videoDriver.isEmpty()) {
481 if (videoDriver == "x11_noaccel") {
482 setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
485 unsetenv("SDL_VIDEO_YUV_HWACCEL");
488 setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
492 previewProps->set("mlt_service", "sdl_audio");
493 previewProps->set("preview_off", 1);
494 previewProps->set("preview_format", mlt_image_rgb24);
495 previewProps->set("terminate_on_pause", 0);
496 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
498 previewProps->set("mlt_service", "sdl_preview");
499 previewProps->set("window_id", m_winid);
500 previewProps->set("terminate_on_pause", 0);
501 //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
503 //m_mltConsumer->set("resize", 1);
504 previewProps->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
505 QString audioDevice = KdenliveSettings::audiodevicename();
506 if (!audioDevice.isEmpty())
507 previewProps->set("audio_device", audioDevice.toUtf8().constData());
509 if (!videoDriver.isEmpty())
510 previewProps->set("video_driver", videoDriver.toUtf8().constData());
512 QString audioDriver = KdenliveSettings::audiodrivername();
514 if (!audioDriver.isEmpty())
515 previewProps->set("audio_driver", audioDriver.toUtf8().constData());
517 previewProps->set("real_time", "0");
518 previewProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
519 mlt_properties_set_data(consumerProperties, "1", previewProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
520 //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-render", this, (mlt_listener) rec_consumer_frame_show);
527 // create an xml producer
528 m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", playlist.toUtf8().constData());
531 // create a producer based on mltproducer parameter
532 m_mltProducer = new Mlt::Producer(*m_mltProfile, playlist.toUtf8().constData());
535 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) {
536 kDebug()<<"//// ERROR CREATRING PROD";
538 delete m_mltConsumer;
539 m_mltConsumer = NULL;
542 delete m_mltProducer;
543 m_mltProducer = NULL;
548 m_mltConsumer->connect(*m_mltProducer);
549 if (m_mltConsumer->start() == -1) {
550 if (m_showFrameEvent) delete m_showFrameEvent;
551 m_showFrameEvent = NULL;
552 delete m_mltConsumer;
553 m_mltConsumer = NULL;
556 m_droppedFramesTimer.start();
561 void MltDeviceCapture::setOverlay(const QString &path)
563 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
564 Mlt::Producer parentProd(m_mltProducer->parent());
565 if (parentProd.get_producer() == NULL) {
566 kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////";
570 Mlt::Service service(parentProd.get_service());
571 if (service.type() != tractor_type) {
572 kWarning() << "// TRACTOR PROBLEM";
575 Mlt::Tractor tractor(service);
576 if ( tractor.count() < 2) {
577 kWarning() << "// TRACTOR PROBLEM";
580 mlt_service_lock(service.get_service());
581 Mlt::Producer trackProducer(tractor.track(0));
582 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
584 trackPlaylist.remove(0);
585 if (path.isEmpty()) {
586 mlt_service_unlock(service.get_service());
591 char *tmp = qstrdup(path.toUtf8().constData());
592 Mlt::Producer *clip = new Mlt::Producer (*m_mltProfile, "loader", tmp);
594 clip->set_in_and_out(0, 99999);
595 trackPlaylist.insert_at(0, clip, 1);
598 mlt_service serv = m_mltProducer->parent().get_service();
599 mlt_service nextservice = mlt_service_get_producer(serv);
600 mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
601 QString mlt_type = mlt_properties_get(properties, "mlt_type");
602 if (mlt_type != "transition") {
603 // transition does not exist, add it
604 Mlt::Field *field = tractor.field();
605 Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, "composite");
606 transition->set_in_and_out(0, 0);
607 transition->set("geometry", "0/0:100%x100%:70");
608 transition->set("fill", 1);
609 transition->set("operator", "and");
610 transition->set("a_track", 0);
611 transition->set("b_track", 1);
612 field->plant_transition(*transition, 0, 1);
614 mlt_service_unlock(service.get_service());
618 void MltDeviceCapture::setOverlayEffect(const QString &tag, const QStringList ¶meters)
620 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
621 Mlt::Service service(m_mltProducer->parent().get_service());
622 Mlt::Tractor tractor(service);
623 Mlt::Producer trackProducer(tractor.track(0));
624 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
625 Mlt::Service trackService(trackProducer.get_service());
627 mlt_service_lock(service.get_service());
629 // delete previous effects
631 filter = trackService.filter(0);
632 if (filter && !tag.isEmpty()) {
633 QString currentService = filter->get("mlt_service");
634 if (currentService == tag) {
635 // Effect is already there
636 mlt_service_unlock(service.get_service());
641 trackService.detach(*filter);
643 filter = trackService.filter(0);
647 mlt_service_unlock(service.get_service());
651 char *tmp = qstrdup(tag.toUtf8().constData());
652 filter = new Mlt::Filter(*m_mltProfile, tmp);
654 if (filter && filter->is_valid()) {
655 for (int j = 0; j < parameters.count(); j++) {
656 filter->set(parameters.at(j).section('=', 0, 0).toUtf8().constData(), parameters.at(j).section('=', 1, 1).toUtf8().constData());
658 trackService.attach(*filter);
660 mlt_service_unlock(service.get_service());
663 void MltDeviceCapture::mirror(bool activate)
665 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
666 Mlt::Service service(m_mltProducer->parent().get_service());
667 Mlt::Tractor tractor(service);
668 Mlt::Producer trackProducer(tractor.track(1));
669 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
670 Mlt::Service trackService(trackProducer.get_service());
672 mlt_service_lock(service.get_service());
674 // delete previous effects
676 filter = trackService.filter(0);
678 trackService.detach(*filter);
680 filter = trackService.filter(0);
684 mlt_service_unlock(service.get_service());
688 filter = new Mlt::Filter(*m_mltProfile, "mirror");
689 if (filter && filter->is_valid()) {
690 filter->set("mirror", "flip");
691 trackService.attach(*filter);
693 mlt_service_unlock(service.get_service());
696 void MltDeviceCapture::uyvy2rgb(unsigned char *yuv_buffer, int width, int height)
698 processingImage = true;
699 QImage image(width, height, QImage::Format_RGB888);
700 unsigned char *rgb_buffer = image.bits();
705 int rgb_ptr, y_ptr, t;
707 len = width * height / 2;
712 for (t = 0; t < len; t++) {
715 Y = yuv_buffer[y_ptr];
716 U = yuv_buffer[y_ptr+1];
717 Y2 = yuv_buffer[y_ptr+2];
718 V = yuv_buffer[y_ptr+3];
721 r = ((298 * (Y - 16) + 409 * (V - 128) + 128) >> 8);
723 g = ((298 * (Y - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8);
725 b = ((298 * (Y - 16) + 516 * (U - 128) + 128) >> 8);
727 if (r > 255) r = 255;
728 if (g > 255) g = 255;
729 if (b > 255) b = 255;
735 rgb_buffer[rgb_ptr] = r;
736 rgb_buffer[rgb_ptr+1] = g;
737 rgb_buffer[rgb_ptr+2] = b;
741 r = ((298 * (Y2 - 16) + 409 * (V - 128) + 128) >> 8);
743 g = ((298 * (Y2 - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8);
745 b = ((298 * (Y2 - 16) + 516 * (U - 128) + 128) >> 8);
747 if (r > 255) r = 255;
748 if (g > 255) g = 255;
749 if (b > 255) b = 255;
755 rgb_buffer[rgb_ptr] = r;
756 rgb_buffer[rgb_ptr+1] = g;
757 rgb_buffer[rgb_ptr+2] = b;
760 //emit imageReady(image);
761 //m_captureDisplayWidget->setImage(image);
762 emit unblockPreview();
763 //processingImage = false;
766 void MltDeviceCapture::slotPreparePreview()
768 QTimer::singleShot(1000, this, SLOT(slotAllowPreview()));
771 void MltDeviceCapture::slotAllowPreview()
773 processingImage = false;
778 #include "mltdevicecapture.moc"