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())
96 profile = KdenliveSettings::current_profile();
97 buildConsumer(profile);
98 connect(this, SIGNAL(unblockPreview()), this, SLOT(slotPreparePreview()));
99 m_droppedFramesTimer.setSingleShot(false);
100 m_droppedFramesTimer.setInterval(1000);
101 connect(&m_droppedFramesTimer, SIGNAL(timeout()), this, SLOT(slotCheckDroppedFrames()));
104 MltDeviceCapture::~MltDeviceCapture()
106 if (m_mltConsumer) delete m_mltConsumer;
107 if (m_mltProducer) delete m_mltProducer;
108 if (m_mltProfile) delete m_mltProfile;
111 void MltDeviceCapture::buildConsumer(const QString &profileName)
113 if (!profileName.isEmpty()) m_activeProfile = profileName;
115 if (m_mltProfile) delete m_mltProfile;
117 char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
118 setenv("MLT_PROFILE", tmp, 1);
119 m_mltProfile = new Mlt::Profile(tmp);
120 m_mltProfile->set_explicit(true);
123 QString videoDriver = KdenliveSettings::videodrivername();
124 if (!videoDriver.isEmpty()) {
125 if (videoDriver == "x11_noaccel") {
126 setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
129 unsetenv("SDL_VIDEO_YUV_HWACCEL");
132 setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
137 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_audio");
138 m_mltConsumer->set("preview_off", 1);
139 m_mltConsumer->set("preview_format", mlt_image_rgb24);
140 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
142 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
143 m_mltConsumer->set("window_id", m_winid);
144 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
146 //m_mltConsumer->set("resize", 1);
147 //m_mltConsumer->set("terminate_on_pause", 1);
148 m_mltConsumer->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
149 //m_mltConsumer->set("rescale", "nearest");
151 QString audioDevice = KdenliveSettings::audiodevicename();
152 if (!audioDevice.isEmpty())
153 m_mltConsumer->set("audio_device", audioDevice.toUtf8().constData());
155 if (!videoDriver.isEmpty())
156 m_mltConsumer->set("video_driver", videoDriver.toUtf8().constData());
158 QString audioDriver = KdenliveSettings::audiodrivername();
160 if (!audioDriver.isEmpty())
161 m_mltConsumer->set("audio_driver", audioDriver.toUtf8().constData());
163 //m_mltConsumer->set("progressive", 0);
164 //m_mltConsumer->set("buffer", 1);
165 //m_mltConsumer->set("real_time", 0);
168 void MltDeviceCapture::pause()
171 m_mltConsumer->set("refresh", 0);
172 //m_mltProducer->set_speed(0.0);
173 m_mltConsumer->purge();
177 void MltDeviceCapture::stop()
179 m_droppedFramesTimer.stop();
180 bool isPlaylist = false;
181 //disconnect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
182 //m_captureDisplayWidget->stop();
184 if (m_showFrameEvent) delete m_showFrameEvent;
185 m_showFrameEvent = NULL;
188 m_mltConsumer->set("refresh", 0);
189 m_mltConsumer->purge();
190 m_mltConsumer->stop();
191 //if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
194 QList <Mlt::Producer *> prods;
195 Mlt::Service service(m_mltProducer->parent().get_service());
196 mlt_service_lock(service.get_service());
197 if (service.type() == tractor_type) {
199 Mlt::Tractor tractor(service);
200 mlt_tractor_close(tractor.get_tractor());
201 Mlt::Field *field = tractor.field();
202 mlt_service nextservice = mlt_service_get_producer(service.get_service());
203 mlt_service nextservicetodisconnect;
204 mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
205 QString mlt_type = mlt_properties_get(properties, "mlt_type");
206 QString resource = mlt_properties_get(properties, "mlt_service");
207 // Delete all transitions
208 while (mlt_type == "transition") {
209 nextservicetodisconnect = nextservice;
210 nextservice = mlt_service_producer(nextservice);
211 mlt_field_disconnect_service(field->get_field(), nextservicetodisconnect);
212 if (nextservice == NULL) break;
213 properties = MLT_SERVICE_PROPERTIES(nextservice);
214 mlt_type = mlt_properties_get(properties, "mlt_type");
215 resource = mlt_properties_get(properties, "mlt_service");
220 mlt_service_unlock(service.get_service());
221 delete m_mltProducer;
222 m_mltProducer = NULL;
224 // For some reason, the consumer seems to be deleted by previous stuff when in playlist mode
225 if (!isPlaylist && m_mltConsumer) delete m_mltConsumer;
226 m_mltConsumer = NULL;
230 void MltDeviceCapture::slotDoRefresh()
232 QMutexLocker locker(&m_mutex);
236 if (m_mltConsumer->is_stopped()) m_mltConsumer->start();
237 m_mltConsumer->purge();
238 m_mltConsumer->set("refresh", 1);
243 void MltDeviceCapture::emitFrameUpdated(Mlt::Frame& frame)
246 //TEST: is it better to convert the frame in a thread outside of MLT??
247 if (processingImage) return;
248 mlt_image_format format = (mlt_image_format) frame.get_int("format"); //mlt_image_rgb24;
249 int width = frame.get_int("width");
250 int height = frame.get_int("height");
251 unsigned char *buffer = (unsigned char *) frame.get_data("image");
252 if (format == mlt_image_yuv422) {
253 QtConcurrent::run(this, &MltDeviceCapture::uyvy2rgb, (unsigned char *) buffer, width, height);
257 mlt_image_format format = mlt_image_rgb24;
260 const uchar* image = frame.get_image(format, width, height);
261 QImage qimage(width, height, QImage::Format_RGB888);
262 //QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
263 memcpy(qimage.bits(), image, width * height * 3);
264 emit frameUpdated(qimage);
267 void MltDeviceCapture::showFrame(Mlt::Frame& frame)
269 mlt_image_format format = mlt_image_rgb24;
272 const uchar* image = frame.get_image(format, width, height);
273 QImage qimage(width, height, QImage::Format_RGB888);
274 memcpy(qimage.scanLine(0), image, width * height * 3);
275 emit showImageSignal(qimage);
277 if (sendFrameForAnalysis && frame.get_frame()->convert_image) {
278 emit frameUpdated(qimage.rgbSwapped());
282 void MltDeviceCapture::showAudio(Mlt::Frame& frame)
284 if (!frame.is_valid() || frame.get_int("test_audio") != 0) {
287 mlt_audio_format audio_format = mlt_audio_s16;
289 int num_channels = 0;
291 int16_t* data = (int16_t*)frame.get_audio(audio_format, freq, num_channels, samples);
297 // Data format: [ c00 c10 c01 c11 c02 c12 c03 c13 ... c0{samples-1} c1{samples-1} for 2 channels.
298 // So the vector is of size samples*channels.
299 QVector<int16_t> sampleVector(samples*num_channels);
300 memcpy(sampleVector.data(), data, samples*num_channels*sizeof(int16_t));
302 emit audioSamplesSignal(sampleVector, freq, num_channels, samples);
306 bool MltDeviceCapture::slotStartPreview(const QString &producer, bool xmlFormat)
308 if (m_mltConsumer == NULL) {
311 char *tmp = qstrdup(producer.toUtf8().constData());
312 if (xmlFormat) m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", tmp);
313 else m_mltProducer = new Mlt::Producer(*m_mltProfile, tmp);
316 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) {
318 delete m_mltProducer;
319 m_mltProducer = NULL;
321 kDebug()<<"//// ERROR CREATRING PROD";
324 m_mltConsumer->connect(*m_mltProducer);
325 if (m_mltConsumer->start() == -1) {
326 delete m_mltConsumer;
327 m_mltConsumer = NULL;
330 m_droppedFramesTimer.start();
331 //connect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
335 void MltDeviceCapture::slotCheckDroppedFrames()
338 int dropped = m_mltProducer->get_int("dropped");
339 if (dropped > m_droppedFrames) {
340 m_droppedFrames = dropped;
341 emit droppedFrames(m_droppedFrames);
346 void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame)
349 int dropped = m_mltProducer->get_int("dropped");
350 if (dropped > m_droppedFrames) {
351 m_droppedFrames = dropped;
352 emit droppedFrames(m_droppedFrames);
356 if (!m_livePreview) return;
357 //if (m_livePreview == 0 && (m_frameCount % 10 > 0)) return;
358 mlt_image_format format = mlt_image_rgb24;
361 uint8_t *data = frame.get_image(format, width, height, 0);
362 //QImage image(width, height, QImage::Format_RGB888);
363 //memcpy(image.bits(), data, width * height * 3);
364 QImage image((uchar *)data, width, height, QImage::Format_RGB888);
366 //m_captureDisplayWidget->setImage(image);
368 //TEST: is it better to process frame conversion ouside MLT???
370 if (!m_livePreview || processingImage) return;
372 mlt_image_format format = (mlt_image_format) frame.get_int("format"); //mlt_image_rgb24a;
373 int width = frame.get_int("width");
374 int height = frame.get_int("height");
375 unsigned char *buffer = (unsigned char *) frame.get_data("image");
376 //unsigned char *buffer = frame.get_image(format, width, height);
377 //convert from uyvy422 to rgba
378 if (format == mlt_image_yuv422) {
379 QtConcurrent::run(this, &MltDeviceCapture::uyvy2rgb, (unsigned char *) buffer, width, height);
380 //CaptureHandler::uyvy2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight());
384 void MltDeviceCapture::saveFrame(Mlt::Frame& frame)
386 mlt_image_format format = mlt_image_rgb24;
389 const uchar* image = frame.get_image(format, width, height);
390 QImage qimage(width, height, QImage::Format_RGB888);
391 memcpy(qimage.bits(), image, width * height * 3);
394 Mlt::Service service(m_mltProducer->parent().get_service());
395 Mlt::Tractor tractor(service);
396 Mlt::Producer trackProducer(tractor.track(0));
397 trackProducer.set("hide", 0);
399 qimage.save(m_capturePath);
400 emit frameSaved(m_capturePath);
401 m_capturePath.clear();
404 void MltDeviceCapture::captureFrame(const QString &path)
406 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
408 // Hide overlay track before doing the capture
409 Mlt::Service service(m_mltProducer->parent().get_service());
410 Mlt::Tractor tractor(service);
411 Mlt::Producer trackProducer(tractor.track(0));
412 mlt_service_lock(service.get_service());
413 trackProducer.set("hide", 1);
414 m_mltConsumer->purge();
415 mlt_service_unlock(service.get_service());
416 m_capturePath = path;
417 // Wait for 5 frames before capture to make sure overlay is gone
421 bool MltDeviceCapture::slotStartCapture(const QString ¶ms, const QString &path, const QString &playlist, bool livePreview, bool xmlPlaylist)
424 m_livePreview = livePreview;
427 if (m_mltProfile) delete m_mltProfile;
428 char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
429 m_mltProfile = new Mlt::Profile(tmp);
431 //m_mltProfile->get_profile()->is_explicit = 1;
434 /*kDebug()<<"-- CREATING CAP: "<<params<<", PATH: "<<path;
435 tmp = qstrdup(QString("avformat:" + path).toUtf8().constData());
436 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, tmp);
437 m_mltConsumer->set("real_time", -KdenliveSettings::mltthreads());
440 m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "multi");
441 if (m_mltConsumer == NULL || !m_mltConsumer->is_valid()) {
443 delete m_mltConsumer;
444 m_mltConsumer = NULL;
449 m_winid = (int) m_captureDisplayWidget->winId();
451 // Create multi consumer setup
452 Mlt::Properties *renderProps = new Mlt::Properties;
453 renderProps->set("mlt_service", "avformat");
454 renderProps->set("target", path.toUtf8().constData());
455 renderProps->set("real_time", -KdenliveSettings::mltthreads());
456 //renderProps->set("terminate_on_pause", 0);
457 renderProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
460 QStringList paramList = params.split(' ', QString::SkipEmptyParts);
462 for (int i = 0; i < paramList.count(); ++i) {
463 tmp = qstrdup(paramList.at(i).section('=', 0, 0).toUtf8().constData());
464 QString value = paramList.at(i).section('=', 1, 1);
465 if (value == "%threads") value = QString::number(QThread::idealThreadCount());
466 tmp2 = qstrdup(value.toUtf8().constData());
467 renderProps->set(tmp, tmp2);
471 mlt_properties consumerProperties = m_mltConsumer->get_properties();
472 mlt_properties_set_data(consumerProperties, "0", renderProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
476 // user wants live preview
477 Mlt::Properties *previewProps = new Mlt::Properties;
478 QString videoDriver = KdenliveSettings::videodrivername();
479 if (!videoDriver.isEmpty()) {
480 if (videoDriver == "x11_noaccel") {
481 setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
484 unsetenv("SDL_VIDEO_YUV_HWACCEL");
487 setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
491 previewProps->set("mlt_service", "sdl_audio");
492 previewProps->set("preview_off", 1);
493 previewProps->set("preview_format", mlt_image_rgb24);
494 previewProps->set("terminate_on_pause", 0);
495 m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
497 previewProps->set("mlt_service", "sdl_preview");
498 previewProps->set("window_id", m_winid);
499 previewProps->set("terminate_on_pause", 0);
500 //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
502 //m_mltConsumer->set("resize", 1);
503 previewProps->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
504 QString audioDevice = KdenliveSettings::audiodevicename();
505 if (!audioDevice.isEmpty())
506 previewProps->set("audio_device", audioDevice.toUtf8().constData());
508 if (!videoDriver.isEmpty())
509 previewProps->set("video_driver", videoDriver.toUtf8().constData());
511 QString audioDriver = KdenliveSettings::audiodrivername();
513 if (!audioDriver.isEmpty())
514 previewProps->set("audio_driver", audioDriver.toUtf8().constData());
516 previewProps->set("real_time", "0");
517 previewProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
518 mlt_properties_set_data(consumerProperties, "1", previewProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
519 //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-render", this, (mlt_listener) rec_consumer_frame_show);
526 // create an xml producer
527 m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", playlist.toUtf8().constData());
530 // create a producer based on mltproducer parameter
531 m_mltProducer = new Mlt::Producer(*m_mltProfile, playlist.toUtf8().constData());
534 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) {
535 kDebug()<<"//// ERROR CREATRING PROD";
537 delete m_mltConsumer;
538 m_mltConsumer = NULL;
541 delete m_mltProducer;
542 m_mltProducer = NULL;
547 m_mltConsumer->connect(*m_mltProducer);
548 if (m_mltConsumer->start() == -1) {
549 if (m_showFrameEvent) delete m_showFrameEvent;
550 m_showFrameEvent = NULL;
551 delete m_mltConsumer;
552 m_mltConsumer = NULL;
555 m_droppedFramesTimer.start();
560 void MltDeviceCapture::setOverlay(const QString &path)
562 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
563 Mlt::Producer parentProd(m_mltProducer->parent());
564 if (parentProd.get_producer() == NULL) {
565 kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////";
569 Mlt::Service service(parentProd.get_service());
570 if (service.type() != tractor_type) {
571 kWarning() << "// TRACTOR PROBLEM";
574 Mlt::Tractor tractor(service);
575 if ( tractor.count() < 2) {
576 kWarning() << "// TRACTOR PROBLEM";
579 mlt_service_lock(service.get_service());
580 Mlt::Producer trackProducer(tractor.track(0));
581 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
583 trackPlaylist.remove(0);
584 if (path.isEmpty()) {
585 mlt_service_unlock(service.get_service());
590 char *tmp = qstrdup(path.toUtf8().constData());
591 Mlt::Producer *clip = new Mlt::Producer (*m_mltProfile, "loader", tmp);
593 clip->set_in_and_out(0, 99999);
594 trackPlaylist.insert_at(0, clip, 1);
597 mlt_service serv = m_mltProducer->parent().get_service();
598 mlt_service nextservice = mlt_service_get_producer(serv);
599 mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
600 QString mlt_type = mlt_properties_get(properties, "mlt_type");
601 if (mlt_type != "transition") {
602 // transition does not exist, add it
603 Mlt::Field *field = tractor.field();
604 Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, "composite");
605 transition->set_in_and_out(0, 0);
606 transition->set("geometry", "0/0:100%x100%:70");
607 transition->set("fill", 1);
608 transition->set("operator", "and");
609 transition->set("a_track", 0);
610 transition->set("b_track", 1);
611 field->plant_transition(*transition, 0, 1);
613 mlt_service_unlock(service.get_service());
617 void MltDeviceCapture::setOverlayEffect(const QString &tag, const QStringList ¶meters)
619 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
620 Mlt::Service service(m_mltProducer->parent().get_service());
621 Mlt::Tractor tractor(service);
622 Mlt::Producer trackProducer(tractor.track(0));
623 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
624 Mlt::Service trackService(trackProducer.get_service());
626 mlt_service_lock(service.get_service());
628 // delete previous effects
630 filter = trackService.filter(0);
631 if (filter && !tag.isEmpty()) {
632 QString currentService = filter->get("mlt_service");
633 if (currentService == tag) {
634 // Effect is already there
635 mlt_service_unlock(service.get_service());
640 trackService.detach(*filter);
642 filter = trackService.filter(0);
646 mlt_service_unlock(service.get_service());
650 char *tmp = qstrdup(tag.toUtf8().constData());
651 filter = new Mlt::Filter(*m_mltProfile, tmp);
653 if (filter && filter->is_valid()) {
654 for (int j = 0; j < parameters.count(); j++) {
655 filter->set(parameters.at(j).section('=', 0, 0).toUtf8().constData(), parameters.at(j).section('=', 1, 1).toUtf8().constData());
657 trackService.attach(*filter);
659 mlt_service_unlock(service.get_service());
662 void MltDeviceCapture::mirror(bool activate)
664 if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
665 Mlt::Service service(m_mltProducer->parent().get_service());
666 Mlt::Tractor tractor(service);
667 Mlt::Producer trackProducer(tractor.track(1));
668 Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
669 Mlt::Service trackService(trackProducer.get_service());
671 mlt_service_lock(service.get_service());
673 // delete previous effects
675 filter = trackService.filter(0);
677 trackService.detach(*filter);
679 filter = trackService.filter(0);
683 mlt_service_unlock(service.get_service());
687 filter = new Mlt::Filter(*m_mltProfile, "mirror");
688 if (filter && filter->is_valid()) {
689 filter->set("mirror", "flip");
690 trackService.attach(*filter);
692 mlt_service_unlock(service.get_service());
695 void MltDeviceCapture::uyvy2rgb(unsigned char *yuv_buffer, int width, int height)
697 processingImage = true;
698 QImage image(width, height, QImage::Format_RGB888);
699 unsigned char *rgb_buffer = image.bits();
704 int rgb_ptr, y_ptr, t;
706 len = width * height / 2;
711 for (t = 0; t < len; t++) {
714 Y = yuv_buffer[y_ptr];
715 U = yuv_buffer[y_ptr+1];
716 Y2 = yuv_buffer[y_ptr+2];
717 V = yuv_buffer[y_ptr+3];
720 r = ((298 * (Y - 16) + 409 * (V - 128) + 128) >> 8);
722 g = ((298 * (Y - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8);
724 b = ((298 * (Y - 16) + 516 * (U - 128) + 128) >> 8);
726 if (r > 255) r = 255;
727 if (g > 255) g = 255;
728 if (b > 255) b = 255;
734 rgb_buffer[rgb_ptr] = r;
735 rgb_buffer[rgb_ptr+1] = g;
736 rgb_buffer[rgb_ptr+2] = b;
740 r = ((298 * (Y2 - 16) + 409 * (V - 128) + 128) >> 8);
742 g = ((298 * (Y2 - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8);
744 b = ((298 * (Y2 - 16) + 516 * (U - 128) + 128) >> 8);
746 if (r > 255) r = 255;
747 if (g > 255) g = 255;
748 if (b > 255) b = 255;
754 rgb_buffer[rgb_ptr] = r;
755 rgb_buffer[rgb_ptr+1] = g;
756 rgb_buffer[rgb_ptr+2] = b;
759 //emit imageReady(image);
760 //m_captureDisplayWidget->setImage(image);
761 emit unblockPreview();
762 //processingImage = false;
765 void MltDeviceCapture::slotPreparePreview()
767 QTimer::singleShot(1000, this, SLOT(slotAllowPreview()));
770 void MltDeviceCapture::slotAllowPreview()
772 processingImage = false;
777 #include "mltdevicecapture.moc"