From 31ed07c68c21990dde342220bb045178b2ac0ea7 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Mon, 1 Nov 2010 21:08:46 +0000 Subject: [PATCH] Stopmotion widget: Improved webcam support, taken from the fswebcam project svn path=/trunk/kdenlive/; revision=5067 --- src/CMakeLists.txt | 7 + src/blackmagic/capture.cpp | 6 +- src/blackmagic/capture.h | 1 + src/kdenlivesettingsdialog.cpp | 6 +- src/mainwindow.cpp | 5 +- src/stopmotion/capturehandler.cpp | 75 ++- src/stopmotion/capturehandler.h | 4 +- src/stopmotion/stopmotion.cpp | 54 +- src/stopmotion/stopmotion.h | 4 +- src/v4l/dec.h | 49 ++ src/v4l/dec_bayer.c | 107 ++++ src/v4l/dec_grey.c | 51 ++ src/v4l/dec_jpeg.c | 109 ++++ src/v4l/dec_rgb.c | 133 +++++ src/v4l/dec_s561.c | 908 ++++++++++++++++++++++++++++++ src/v4l/dec_yuv.c | 170 ++++++ src/v4l/src.c | 4 +- src/v4l/src.h | 9 +- src/v4l/src_v4l2.c | 12 +- src/v4l/v4lcapture.cpp | 122 +++- src/v4l/v4lcapture.h | 5 + 21 files changed, 1795 insertions(+), 46 deletions(-) create mode 100644 src/v4l/dec.h create mode 100644 src/v4l/dec_bayer.c create mode 100644 src/v4l/dec_grey.c create mode 100644 src/v4l/dec_jpeg.c create mode 100644 src/v4l/dec_rgb.c create mode 100644 src/v4l/dec_s561.c create mode 100644 src/v4l/dec_yuv.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 65a69c3f..501af427 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -269,6 +269,12 @@ if (NOT APPLE) v4l/v4lcapture.cpp v4l/src.c v4l/src_v4l2.c + v4l/dec_bayer.c + v4l/dec_grey.c + v4l/dec_jpeg.c + v4l/dec_rgb.c + v4l/dec_s561.c + v4l/dec_yuv.c ) endif (NOT APPLE) @@ -277,6 +283,7 @@ endif (NOT APPLE) find_library( DL_LIB NAMES ${CMAKE_DL_LIBS} ) MESSAGE( STATUS "using dl library: ${DL_LIB}" ) + kde4_add_kcfg_files(kdenlive_SRCS kdenlivesettings.kcfgc ) QT4_ADD_DBUS_ADAPTOR(kdenlive_SRCS org.kdenlive.MainWindow.xml mainwindow.h MainWindow) kde4_add_executable(kdenlive ${kdenlive_SRCS} ${kdenlive_UI}) diff --git a/src/blackmagic/capture.cpp b/src/blackmagic/capture.cpp index 505c0858..2989cacf 100644 --- a/src/blackmagic/capture.cpp +++ b/src/blackmagic/capture.cpp @@ -331,7 +331,7 @@ void DeckLinkCaptureDelegate::slotProcessFrame() } else { QImage image(videoFrame->GetWidth(), videoFrame->GetHeight(), QImage::Format_ARGB32_Premultiplied); //convert from uyvy422 to rgba - CaptureHandler::yuv2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight()); + CaptureHandler::uyvy2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight()); image.save(capturePath); emit frameSaved(capturePath); } @@ -814,6 +814,10 @@ void BmdCaptureHandler::hideOverlay() if (previewView) previewView->hideOverlay(); } +void BmdCaptureHandler::setDevice(const QString , QString) +{ +} + void BmdCaptureHandler::hidePreview(bool hide) { if (previewView) previewView->setHidden(hide); diff --git a/src/blackmagic/capture.h b/src/blackmagic/capture.h index 1a7942ec..1be79adb 100644 --- a/src/blackmagic/capture.h +++ b/src/blackmagic/capture.h @@ -60,6 +60,7 @@ public: void hideOverlay(); void hidePreview(bool hide); QStringList getDeviceName(QString); + void setDevice(const QString input, QString size = QString()); private: IDeckLinkIterator *deckLinkIterator; diff --git a/src/kdenlivesettingsdialog.cpp b/src/kdenlivesettingsdialog.cpp index e752b39a..035408a3 100644 --- a/src/kdenlivesettingsdialog.cpp +++ b/src/kdenlivesettingsdialog.cpp @@ -89,8 +89,10 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(QWidget * parent) : QString path = "/dev/video" + QString::number(i); if (QFile::exists(path)) { QStringList deviceInfo = v4l.getDeviceName(path); - m_configCapture.kcfg_detectedv4ldevices->addItem(deviceInfo.at(0), path); - m_configCapture.kcfg_detectedv4ldevices->setItemData(m_configCapture.kcfg_detectedv4ldevices->count() - 1, deviceInfo.at(1), Qt::UserRole + 1); + if (!deviceInfo.isEmpty()) { + m_configCapture.kcfg_detectedv4ldevices->addItem(deviceInfo.at(0), path); + m_configCapture.kcfg_detectedv4ldevices->setItemData(m_configCapture.kcfg_detectedv4ldevices->count() - 1, deviceInfo.at(1), Qt::UserRole + 1); + } } } connect(m_configCapture.kcfg_detectedv4ldevices, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdatev4lDevice())); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1dfe6e49..d578f119 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -553,6 +553,9 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & MainWindow::~MainWindow() { + if (m_stopmotion) { + delete m_stopmotion; + } m_effectStack->slotClipItemSelected(NULL, 0); m_transitionConfig->slotTransitionItemSelected(NULL, 0, QPoint(), false); @@ -2508,6 +2511,7 @@ void MainWindow::slotPreferences(int page, int option) * cached, in which case you want to display the cached dialog * instead of creating another one */ + if (m_stopmotion) m_stopmotion->slotLive(false); if (KConfigDialog::showDialog("settings")) { KdenliveSettingsDialog* d = static_cast (KConfigDialog::exists("settings")); if (page != -1) d->showPage(page, option); @@ -4015,7 +4019,6 @@ void MainWindow::slotOpenStopmotion() m_stopmotion->show(); } - void MainWindow::slotDeleteClip(const QString &id) { QList list = findChildren(); diff --git a/src/stopmotion/capturehandler.cpp b/src/stopmotion/capturehandler.cpp index 38ee07e6..fc3a9b49 100644 --- a/src/stopmotion/capturehandler.cpp +++ b/src/stopmotion/capturehandler.cpp @@ -38,7 +38,7 @@ void CaptureHandler::stopCapture() } //static -void CaptureHandler::yuv2rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffer, int width, int height) +void CaptureHandler::uyvy2rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffer, int width, int height) { int len; int r, g, b; @@ -112,5 +112,78 @@ void CaptureHandler::yuv2rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffe } } +void CaptureHandler::yuyv2rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffer, int width, int height) +{ + int len; + int r, g, b; + int Y, U, V, Y2; + int rgb_ptr, y_ptr, t; + + len = width * height / 2; + + rgb_ptr = 0; + y_ptr = 0; + + for (t = 0; t < len; t++) { /* process 2 pixels at a time */ + /* Compute parts of the UV components */ + + Y = yuv_buffer[y_ptr]; + U = yuv_buffer[y_ptr+1]; + Y2 = yuv_buffer[y_ptr+2]; + V = yuv_buffer[y_ptr+3]; + y_ptr += 4; + + + /*r = 1.164*(Y-16) + 1.596*(V-128); + g = 1.164*(Y-16) - 0.813*(V-128) - 0.391*(U-128); + b = 1.164*(Y-16) + 2.018*(U-128);*/ + + + r = ((298 * (Y - 16) + 409 * (V - 128) + 128) >> 8); + + g = ((298 * (Y - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8); + + b = ((298 * (Y - 16) + 516 * (U - 128) + 128) >> 8); + + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; + + if (r < 0) r = 0; + if (g < 0) g = 0; + if (b < 0) b = 0; + + rgb_buffer[rgb_ptr] = b; + rgb_buffer[rgb_ptr+1] = g; + rgb_buffer[rgb_ptr+2] = r; + rgb_buffer[rgb_ptr+3] = 255; + + rgb_ptr += 4; + /*r = 1.164*(Y2-16) + 1.596*(V-128); + g = 1.164*(Y2-16) - 0.813*(V-128) - 0.391*(U-128); + b = 1.164*(Y2-16) + 2.018*(U-128);*/ + + + r = ((298 * (Y2 - 16) + 409 * (V - 128) + 128) >> 8); + + g = ((298 * (Y2 - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8); + + b = ((298 * (Y2 - 16) + 516 * (U - 128) + 128) >> 8); + + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; + + if (r < 0) r = 0; + if (g < 0) g = 0; + if (b < 0) b = 0; + + rgb_buffer[rgb_ptr] = b; + rgb_buffer[rgb_ptr+1] = g; + rgb_buffer[rgb_ptr+2] = r; + rgb_buffer[rgb_ptr+3] = 255; + rgb_ptr += 4; + } +} diff --git a/src/stopmotion/capturehandler.h b/src/stopmotion/capturehandler.h index 342a2510..947111ab 100644 --- a/src/stopmotion/capturehandler.h +++ b/src/stopmotion/capturehandler.h @@ -39,7 +39,9 @@ public: virtual void hideOverlay() = 0; virtual void hidePreview(bool hide) = 0; virtual QStringList getDeviceName(QString input) = 0; - static void yuv2rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffer, int width, int height); + virtual void setDevice(const QString input, QString size = QString()) = 0; + static void uyvy2rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffer, int width, int height); + static void yuyv2rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffer, int width, int height); protected: QVBoxLayout *m_layout; diff --git a/src/stopmotion/stopmotion.cpp b/src/stopmotion/stopmotion.cpp index 46c33f52..3a2dbd2b 100644 --- a/src/stopmotion/stopmotion.cpp +++ b/src/stopmotion/stopmotion.cpp @@ -97,6 +97,7 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, const QList< QAction * > , m_sequenceFrame(0) , m_animatedIndex(-1) { + //setAttribute(Qt::WA_DeleteOnClose); addActions(actions); setupUi(this); setWindowTitle(i18n("Stop Motion Capture")); @@ -191,13 +192,36 @@ StopmotionWidget::StopmotionWidget(KUrl projectFolder, const QList< QAction * > } if (QFile::exists(KdenliveSettings::video4vdevice())) { #ifndef Q_WS_MAC - if (m_bmCapture == NULL) m_bmCapture = new V4lCaptureHandler(m_layout); - capture_device->addItem(m_bmCapture->getDeviceName(KdenliveSettings::video4vdevice()).at(0), "v4l"); + V4lCaptureHandler v4l(NULL); + // Video 4 Linux device detection + for (int i = 0; i < 10; i++) { + QString path = "/dev/video" + QString::number(i); + if (QFile::exists(path)) { + QStringList deviceInfo = v4l.getDeviceName(path); + if (!deviceInfo.isEmpty()) { + capture_device->addItem(deviceInfo.at(0), "v4l"); + capture_device->setItemData(capture_device->count() - 1, path, Qt::UserRole + 1); + capture_device->setItemData(capture_device->count() - 1, deviceInfo.at(1), Qt::UserRole + 2); + if (path == KdenliveSettings::video4vdevice()) capture_device->setCurrentIndex(capture_device->count() - 1); + } + } + } + + /*V4lCaptureHandler v4lhandler(NULL); + QStringList deviceInfo = v4lhandler.getDeviceName(KdenliveSettings::video4vdevice()); + capture_device->addItem(deviceInfo.at(0), "v4l"); + capture_device->setItemData(capture_device->count() - 1, deviceInfo.at(3), Qt::UserRole + 1);*/ + if (m_bmCapture == NULL) { + m_bmCapture = new V4lCaptureHandler(m_layout); + m_bmCapture->setDevice(capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString(), capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 2).toString()); + } #endif } - connect(m_bmCapture, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString))); connect(capture_device, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHandler())); + if (m_bmCapture) { + connect(m_bmCapture, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString))); + } else live_button->setEnabled(false); m_frame_preview = new MyLabel(this); connect(m_frame_preview, SIGNAL(seek(bool)), this, SLOT(slotSeekFrame(bool))); connect(m_frame_preview, SIGNAL(switchToLive()), this, SLOT(slotSwitchLive())); @@ -269,17 +293,21 @@ void StopmotionWidget::slotIntervalCapture(bool capture) void StopmotionWidget::slotUpdateHandler() { QString data = capture_device->itemData(capture_device->currentIndex()).toString(); - m_bmCapture->stopPreview(); - delete m_bmCapture; + slotLive(false); + if (m_bmCapture) { + delete m_bmCapture; + } m_layout->removeWidget(m_frame_preview); if (data == "v4l") { #ifndef Q_WS_MAC m_bmCapture = new V4lCaptureHandler(m_layout); + m_bmCapture->setDevice(capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString(), capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 2).toString()); #endif } else { m_bmCapture = new BmdCaptureHandler(m_layout); - connect(m_bmCapture, SIGNAL(gotMessage(const QString &)), this, SLOT(slotGotHDMIMessage(const QString &))); + if (m_bmCapture) connect(m_bmCapture, SIGNAL(gotMessage(const QString &)), this, SLOT(slotGotHDMIMessage(const QString &))); } + live_button->setEnabled(m_bmCapture != NULL); m_layout->addWidget(m_frame_preview); } @@ -307,24 +335,24 @@ void StopmotionWidget::slotSwitchLive() { setUpdatesEnabled(false); if (m_frame_preview->isHidden()) { - m_bmCapture->hidePreview(true); + if (m_bmCapture) m_bmCapture->hidePreview(true); m_frame_preview->setHidden(false); } else { m_frame_preview->setHidden(true); - m_bmCapture->hidePreview(false); + if (m_bmCapture) m_bmCapture->hidePreview(false); } setUpdatesEnabled(true); } void StopmotionWidget::slotLive(bool isOn) { - if (isOn) { + if (isOn && m_bmCapture) { //m_frame_preview->setImage(QImage()); m_frame_preview->setHidden(true); m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode(), false); capture_button->setEnabled(true); } else { - m_bmCapture->stopPreview(); + if (m_bmCapture) m_bmCapture->stopPreview(); m_frame_preview->setHidden(false); capture_button->setEnabled(false); live_button->setChecked(false); @@ -337,13 +365,14 @@ void StopmotionWidget::slotShowOverlay(bool isOn) if (live_button->isChecked() && m_sequenceFrame > 0) { slotUpdateOverlay(); } - } else { + } else if (m_bmCapture) { m_bmCapture->hideOverlay(); } } void StopmotionWidget::slotUpdateOverlay() { + if (m_bmCapture == NULL) return; QString path = getPathForFrame(m_sequenceFrame - 1); if (!QFile::exists(path)) return; QImage img(path); @@ -408,6 +437,7 @@ void StopmotionWidget::sequenceNameChanged(const QString &name) void StopmotionWidget::slotCaptureFrame() { + if (m_bmCapture == NULL) return; if (sequence_name->currentText().isEmpty()) { QString seqName = QInputDialog::getText(this, i18n("Create New Sequence"), i18n("Enter sequence name")); if (seqName.isEmpty()) return; @@ -484,7 +514,7 @@ void StopmotionWidget::slotShowFrame(const QString &path) QImage img(path); capture_button->setEnabled(false); if (!img.isNull()) { - m_bmCapture->hidePreview(true); + if (m_bmCapture) m_bmCapture->hidePreview(true); m_frame_preview->setImage(img); m_frame_preview->setHidden(false); m_frame_preview->update(); diff --git a/src/stopmotion/stopmotion.h b/src/stopmotion/stopmotion.h index bd74a521..9da28ad6 100644 --- a/src/stopmotion/stopmotion.h +++ b/src/stopmotion/stopmotion.h @@ -120,11 +120,13 @@ private: int m_effectIndex; #endif -private slots: +public slots: /** @brief Display the live feed from capture device. @param isOn enable or disable the feature */ void slotLive(bool isOn); +private slots: + /** @brief Display the last captured frame over current live feed. @param isOn enable or disable the feature */ void slotShowOverlay(bool isOn); diff --git a/src/v4l/dec.h b/src/v4l/dec.h new file mode 100644 index 00000000..75a5a1f4 --- /dev/null +++ b/src/v4l/dec.h @@ -0,0 +1,49 @@ +/* fswebcam - Small and simple webcam for *nix */ +/*============================================================*/ +/* Copyright (C)2005-2010 Philip Heron */ +/* */ +/* This program is distributed under the terms of the GNU */ +/* General Public License, version 2. You may use, modify, */ +/* and redistribute it under the terms of this license. A */ +/* copy should be included with this source. */ + +#ifdef __cplusplus +extern "C" { + #endif + +#ifndef INC_DEC_H +#define INC_DEC_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +extern int fswc_add_image_bayer(avgbmp_t *dst, uint8_t *img, uint32_t length, uint32_t w, uint32_t h, int palette); + +extern int fswc_add_image_y16(src_t *src, avgbmp_t *abitmap); +extern int fswc_add_image_grey(src_t *src, avgbmp_t *abitmap); + +extern int verify_jpeg_dht(uint8_t *src, uint32_t lsrc, uint8_t **dst, uint32_t *ldst); + +extern int fswc_add_image_png(src_t *src, avgbmp_t *abitmap); + +extern int fswc_add_image_rgb32(src_t *src, avgbmp_t *abitmap); +extern int fswc_add_image_bgr32(src_t *src, avgbmp_t *abitmap); +extern int fswc_add_image_rgb24(src_t *src, avgbmp_t *abitmap); +extern int fswc_add_image_bgr24(src_t *src, avgbmp_t *abitmap); +extern int fswc_add_image_rgb565(src_t *src, avgbmp_t *abitmap); +extern int fswc_add_image_rgb555(src_t *src, avgbmp_t *abitmap); + +extern int fswc_add_image_yuyv(src_t *src, avgbmp_t *abitmap); +extern int fswc_add_image_yuv420p(src_t *src, avgbmp_t *abitmap); +extern int fswc_add_image_nv12mb(src_t *src, avgbmp_t *abitmap); + +extern int fswc_add_image_s561(avgbmp_t *dst, uint8_t *img, uint32_t length, uint32_t width, uint32_t height, int palette); + +#endif + +#ifdef __cplusplus +} +#endif + + diff --git a/src/v4l/dec_bayer.c b/src/v4l/dec_bayer.c new file mode 100644 index 00000000..ba27e85e --- /dev/null +++ b/src/v4l/dec_bayer.c @@ -0,0 +1,107 @@ +/* fswebcam - Small and simple webcam for *nix */ +/*============================================================*/ +/* Copyright (C)2005-2010 Philip Heron */ +/* */ +/* This program is distributed under the terms of the GNU */ +/* General Public License, version 2. You may use, modify, */ +/* and redistribute it under the terms of this license. A */ +/* copy should be included with this source. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +/*#include "fswebcam.h"*/ +#include "src.h" + + +int fswc_add_image_bayer(avgbmp_t *dst, uint8_t *img, uint32_t length, uint32_t w, uint32_t h, int palette) +{ + uint32_t x = 0, y = 0; + uint32_t i = w * h; + + if(length < i) return(-1); + + /* SBGGR8 bayer pattern: + * + * BGBGBGBGBG + * GRGRGRGRGR + * BGBGBGBGBG + * GRGRGRGRGR + * + * SGBRG8 bayer pattern: + * + * GBGBGBGBGB + * RGRGRGRGRG + * GBGBGBGBGB + * RGRGRGRGRG + * + * SGRBG8 bayer pattern: + * + * GRGRGRGRGR + * BGBGBGBGBG + * GRGRGRGRGR + * BGBGBGBGBG + */ + + while(i-- > 0) + { + uint8_t *p[8]; + uint8_t hn, vn, di; + uint8_t r, g, b; + int mode; + + /* Setup pointers to this pixel's neighbours. */ + p[0] = img - w - 1; + p[1] = img - w; + p[2] = img - w + 1; + p[3] = img - 1; + p[4] = img + 1; + p[5] = img + w - 1; + p[6] = img + w; + p[7] = img + w + 1; + + /* Juggle pointers if they are out of bounds. */ + if(!y) { p[0]=p[5]; p[1]=p[6]; p[2]=p[7]; } + else if(y == h - 1) { p[5]=p[0]; p[6]=p[1]; p[7]=p[2]; } + if(!x) { p[0]=p[2]; p[3]=p[4]; p[5]=p[7]; } + else if(x == w - 1) { p[2]=p[0]; p[4]=p[3]; p[7]=p[5]; } + + /* Average matching neighbours. */ + hn = (*p[3] + *p[4]) / 2; + vn = (*p[1] + *p[6]) / 2; + di = (*p[0] + *p[2] + *p[5] + *p[7]) / 4; + + /* Calculate RGB */ + if(palette == SRC_PAL_BAYER) mode = (x + y) & 0x01; + else mode = ~(x + y) & 0x01; + + if(mode) + { + g = *img; + if(y & 0x01) { r = hn; b = vn; } + else { r = vn; b = hn; } + } + else if(y & 0x01) { r = *img; g = (vn + hn) / 2; b = di; } + else { b = *img; g = (vn + hn) / 2; r = di; } + + if(palette == SRC_PAL_SGRBG8) + { + uint8_t t = r; + r = b; + b = t; + } + + *(dst++) += r; + *(dst++) += g; + *(dst++) += b; + + /* Move to the next pixel (or line) */ + if(++x == w) { x = 0; y++; } + img++; + } + + return(0); +} + diff --git a/src/v4l/dec_grey.c b/src/v4l/dec_grey.c new file mode 100644 index 00000000..28cfbfd7 --- /dev/null +++ b/src/v4l/dec_grey.c @@ -0,0 +1,51 @@ +/* fswebcam - Small and simple webcam for *nix */ +/*============================================================*/ +/* Copyright (C)2005-2010 Philip Heron */ +/* */ +/* This program is distributed under the terms of the GNU */ +/* General Public License, version 2. You may use, modify, */ +/* and redistribute it under the terms of this license. A */ +/* copy should be included with this source. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "src.h" + +int fswc_add_image_y16(src_t *src, avgbmp_t *abitmap) +{ + uint16_t *bitmap = (uint16_t *) src->img; + uint32_t i = src->width * src->height; + + if(src->length < i) return(-1); + + while(i-- > 0) + { + *(abitmap++) += *bitmap >> 8; + *(abitmap++) += *bitmap >> 8; + *(abitmap++) += *(bitmap++) >> 8; + } + + return(0); +} + +int fswc_add_image_grey(src_t *src, avgbmp_t *abitmap) +{ + uint8_t *bitmap = (uint8_t *) src->img; + uint32_t i = src->width * src->height; + + if(src->length < i) return(-1); + + while(i-- > 0) + { + *(abitmap++) += *bitmap; + *(abitmap++) += *bitmap; + *(abitmap++) += *(bitmap++); + } + + return(0); +} + diff --git a/src/v4l/dec_jpeg.c b/src/v4l/dec_jpeg.c new file mode 100644 index 00000000..2d94d8ec --- /dev/null +++ b/src/v4l/dec_jpeg.c @@ -0,0 +1,109 @@ +/* fswebcam - Small and simple webcam for *nix */ +/*============================================================*/ +/* Copyright (C)2005-2010 Philip Heron */ +/* */ +/* This program is distributed under the terms of the GNU */ +/* General Public License, version 2. You may use, modify, */ +/* and redistribute it under the terms of this license. A */ +/* copy should be included with this source. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "src.h" + +int verify_jpeg_dht(uint8_t *src, uint32_t lsrc, + uint8_t **dst, uint32_t *ldst) +{ + /* This function is based on a patch provided by Scott J. Bertin. */ + + static unsigned char dht[] = + { + 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, + 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, + 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, + 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, + 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, + 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, + 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, + 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, + 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, + 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa + }; + uint8_t *p, *i = NULL; + + /* By default we simply return the source image. */ + *dst = src; + *ldst = lsrc; + + /* Scan for an existing DHT segment or the first SOS segment. */ + for(p = src + 2; p - src < lsrc - 3 && i == NULL; ) + { + if(*(p++) != 0xFF) continue; + + if(*p == 0xD9) break; /* JPEG_EOI */ + if(*p == 0xC4) return(0); /* JPEG_DHT */ + if(*p == 0xDA && !i) i = p - 1; /* JPEG_SOS */ + + /* Move to next segment. */ + p += (p[1] << 8) + p[2]; + } + + /* If no SOS was found, insert the DHT directly after the SOI. */ + if(i == NULL) i = src + 2; + + + *ldst = lsrc + sizeof(dht); + *dst = malloc(*ldst); + if(!*dst) + { + return(-1); + } + + /* Copy the JPEG data, inserting the DHT segment. */ + memcpy((p = *dst), src, i - src); + memcpy((p += i - src), dht, sizeof(dht)); + memcpy((p += sizeof(dht)), i, lsrc - (i - src)); + + return(1); +} + + + diff --git a/src/v4l/dec_rgb.c b/src/v4l/dec_rgb.c new file mode 100644 index 00000000..ab768578 --- /dev/null +++ b/src/v4l/dec_rgb.c @@ -0,0 +1,133 @@ +/* fswebcam - Small and simple webcam for *nix */ +/*============================================================*/ +/* Copyright (C)2005-2010 Philip Heron */ +/* */ +/* This program is distributed under the terms of the GNU */ +/* General Public License, version 2. You may use, modify, */ +/* and redistribute it under the terms of this license. A */ +/* copy should be included with this source. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "src.h" + +int fswc_add_image_rgb32(src_t *src, avgbmp_t *abitmap) +{ + uint8_t *img = (uint8_t *) src->img; + uint32_t i = src->width * src->height; + + if(src->length << 2 < i) return(-1); + + while(i-- > 0) + { + *(abitmap++) += *(img++); + *(abitmap++) += *(img++); + *(abitmap++) += *(img++); + img++; + } + + return(0); +} + +int fswc_add_image_bgr32(src_t *src, avgbmp_t *abitmap) +{ + uint8_t *img = (uint8_t *) src->img; + uint32_t p, i = src->width * src->height; + + if(src->length << 2 < i) return(-1); + + for(p = 0; p < i; p += 4) + { + abitmap[0] += img[2]; + abitmap[1] += img[1]; + abitmap[2] += img[0]; + abitmap += 3; + img += 4; + } + + return(0); +} + +int fswc_add_image_rgb24(src_t *src, avgbmp_t *abitmap) +{ + uint8_t *img = (uint8_t *) src->img; + uint32_t i = src->width * src->height * 3; + + if(src->length < i) return(-1); + while(i-- > 0) *(abitmap++) += *(img++); + + return(0); +} + +int fswc_add_image_bgr24(src_t *src, avgbmp_t *abitmap) +{ + uint8_t *img = (uint8_t *) src->img; + uint32_t p, i = src->width * src->height * 3; + + if(src->length < i) return(-1); + + for(p = 0; p < src->length; p += 3) + { + abitmap[0] += img[2]; + abitmap[1] += img[1]; + abitmap[2] += img[0]; + abitmap += 3; + img += 3; + } + + return(0); +} + +int fswc_add_image_rgb565(src_t *src, avgbmp_t *abitmap) +{ + uint16_t *img = (uint16_t *) src->img; + uint32_t i = src->width * src->height; + + if(src->length >> 1 < i) return(-1); + + while(i-- > 0) + { + uint8_t r, g, b; + + r = (*img & 0xF800) >> 8; + g = (*img & 0x7E0) >> 3; + b = (*img & 0x1F) << 3; + + *(abitmap++) += r + (r >> 5); + *(abitmap++) += g + (g >> 6); + *(abitmap++) += b + (b >> 5); + + img++; + } + + return(0); +} + +int fswc_add_image_rgb555(src_t *src, avgbmp_t *abitmap) +{ + uint16_t *img = (uint16_t *) src->img; + uint32_t i = src->width * src->height; + + if(src->length >> 1 < i) return(-1); + + while(i-- > 0) + { + uint8_t r, g, b; + + r = (*img & 0x7C00) >> 7; + g = (*img & 0x3E0) >> 2; + b = (*img & 0x1F) << 3; + + *(abitmap++) += r + (r >> 5); + *(abitmap++) += g + (g >> 5); + *(abitmap++) += b + (b >> 5); + + img++; + } + + return(0); +} + diff --git a/src/v4l/dec_s561.c b/src/v4l/dec_s561.c new file mode 100644 index 00000000..ae1bc4fc --- /dev/null +++ b/src/v4l/dec_s561.c @@ -0,0 +1,908 @@ +/* Spca561decoder (C) 2005 Andrzej Szombierski [qq@kuku.eu.org] */ +/*==============================================================*/ +/* This program is distributed under the terms of the GNU */ +/* General Public License, version 2. You may use, modify, */ +/* and redistribute it under the terms of this license. A */ +/* copy should be included with this source. */ + +/* + * Decoder for compressed spca561 images + * It was developed for "Labtec WebCam Elch 2(SPCA561A)" (046d:0929) + * but it might work with other spca561 cameras + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "src.h" +#include "dec.h" + +/*fixme: not reentrant */ +static unsigned int bit_bucket; +static const unsigned char *input_ptr; + +static void refill(int *bitfill) +{ + if (*bitfill < 8) { + bit_bucket = (bit_bucket << 8) | *(input_ptr++); + *bitfill += 8; + } +} + +static int nbits(int *bitfill, int n) +{ + bit_bucket = (bit_bucket << 8) | *(input_ptr++); + *bitfill -= n; + return (bit_bucket >> (*bitfill & 0xff)) & ((1 << n) - 1); +} + +static int _nbits(int *bitfill, int n) +{ + *bitfill -= n; + return (bit_bucket >> (*bitfill & 0xff)) & ((1 << n) - 1); +} + +static int fun_A(int *bitfill) +{ + int ret; + static int tab[] = { + 12, 13, 14, 15, 16, 17, 18, 19, -12, -13, -14, -15, + -16, -17, -18, -19, -19 + }; + + ret = tab[nbits(bitfill, 4)]; + + refill(bitfill); + return ret; +} +static int fun_B(int *bitfill) +{ + static int tab1[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 16, 17, + 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 + }; + static int tab[] = + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -5, + -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, + -18, -19 + }; + unsigned int tmp; + + tmp = nbits(bitfill, 7) - 68; + refill(bitfill); + if (tmp > 47) + return 0xff; + return tab[tab1[tmp]]; +} +static int fun_C(int *bitfill, int gkw) +{ + static int tab1[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 12, 13, + 14, + 15, 16, 17, 18, 19, 20, 21, 22 + }; + static int tab[] = + { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -9, -10, -11, + -12, -13, -14, -15, -16, -17, -18, -19 + }; + unsigned int tmp; + + if (gkw == 0xfe) { + if (nbits(bitfill, 1) == 0) + return 7; + else + return -8; + } + + if (gkw != 0xff) + return 0xff; + + tmp = nbits(bitfill, 7) - 72; + if (tmp > 43) + return 0xff; + + refill(bitfill); + return tab[tab1[tmp]]; +} +static int fun_D(int *bitfill, int gkw) +{ + if (gkw == 0xfd) { + if (nbits(bitfill, 1) == 0) + return 12; + return -13; + } + + if (gkw == 0xfc) { + if (nbits(bitfill, 1) == 0) + return 13; + return -14; + } + + if (gkw == 0xfe) { + switch (nbits(bitfill, 2)) { + case 0: + return 14; + case 1: + return -15; + case 2: + return 15; + case 3: + return -16; + } + } + + if (gkw == 0xff) { + switch (nbits(bitfill, 3)) { + case 4: + return 16; + case 5: + return -17; + case 6: + return 17; + case 7: + return -18; + case 2: + return _nbits(bitfill, 1) ? 0xed : 0x12; + case 3: + (*bitfill)--; + return 18; + } + return 0xff; + } + return gkw; +} + +static int fun_E(int cur_byte, int *bitfill) +{ + static int tab0[] = { 0, -1, 1, -2, 2, -3, 3, -4 }; + static int tab1[] = { 4, -5, 5, -6, 6, -7, 7, -8 }; + static int tab2[] = { 8, -9, 9, -10, 10, -11, 11, -12 }; + static int tab3[] = { 12, -13, 13, -14, 14, -15, 15, -16 }; + static int tab4[] = { 16, -17, 17, -18, 18, -19, 19, -19 }; + + if ((cur_byte & 0xf0) >= 0x80) { + *bitfill -= 4; + return tab0[(cur_byte >> 4) & 7]; + } + if ((cur_byte & 0xc0) == 0x40) { + *bitfill -= 5; + return tab1[(cur_byte >> 3) & 7]; + + } + if ((cur_byte & 0xe0) == 0x20) { + *bitfill -= 6; + return tab2[(cur_byte >> 2) & 7]; + + } + if ((cur_byte & 0xf0) == 0x10) { + *bitfill -= 7; + return tab3[(cur_byte >> 1) & 7]; + + } + if ((cur_byte & 0xf8) == 8) { + *bitfill -= 8; + return tab4[cur_byte & 7]; + } + return 0xff; +} + +static int fun_F(int cur_byte, int *bitfill) +{ + *bitfill -= 5; + switch (cur_byte & 0xf8) { + case 0x80: + return 0; + case 0x88: + return -1; + case 0x90: + return 1; + case 0x98: + return -2; + case 0xa0: + return 2; + case 0xa8: + return -3; + case 0xb0: + return 3; + case 0xb8: + return -4; + case 0xc0: + return 4; + case 0xc8: + return -5; + case 0xd0: + return 5; + case 0xd8: + return -6; + case 0xe0: + return 6; + case 0xe8: + return -7; + case 0xf0: + return 7; + case 0xf8: + return -8; + } + + *bitfill -= 1; + switch (cur_byte & 0xfc) { + case 0x40: + return 8; + case 0x44: + return -9; + case 0x48: + return 9; + case 0x4c: + return -10; + case 0x50: + return 10; + case 0x54: + return -11; + case 0x58: + return 11; + case 0x5c: + return -12; + case 0x60: + return 12; + case 0x64: + return -13; + case 0x68: + return 13; + case 0x6c: + return -14; + case 0x70: + return 14; + case 0x74: + return -15; + case 0x78: + return 15; + case 0x7c: + return -16; + } + + *bitfill -= 1; + switch (cur_byte & 0xfe) { + case 0x20: + return 16; + case 0x22: + return -17; + case 0x24: + return 17; + case 0x26: + return -18; + case 0x28: + return 18; + case 0x2a: + return -19; + case 0x2c: + return 19; + } + + *bitfill += 7; + return 0xff; +} + +static int spca561_decode(int width, int height, + const unsigned char *inbuf, + unsigned char *outbuf) +{ + /* buffers */ + static int accum[8 * 8 * 8]; + static int i_hits[8 * 8 * 8]; + + const int nbits_A[] = + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, 1, + 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, + 7, 7, + 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, + 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + }; + const int tab_A[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 11, -11, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, + 255, 254, -4, + -4, -5, -5, -6, -6, -7, -7, -8, -8, -9, -9, -10, -10, -1, + -1, -1, + -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, + 3, 3, 3, + -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3, + -3, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, + 1 + }; + + const int nbits_B[] = + { 0, 8, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, + 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + const int tab_B[] = + { 0xff, -4, 3, 3, -3, -3, -3, -3, 2, 2, 2, 2, 2, 2, 2, 2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + }; + + const int nbits_C[] = + { 0, 0, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + }; + const int tab_C[] = + { 0xff, 0xfe, 6, -7, 5, 5, -6, -6, 4, 4, 4, 4, -5, -5, -5, -5, + 3, 3, 3, 3, 3, 3, 3, 3, -4, -4, -4, -4, -4, -4, -4, -4, 2, + 2, 2, 2, + 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, -3, -3, -3, -3, -3, -3, -3, -3, + -3, -3, + -3, -3, -3, + -3, -3, -3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, + -2, -2, + -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, + -2, -2, + -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, + }; + + const int nbits_D[] = + { 0, 0, 0, 0, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, + 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, + 4, 4, + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, + 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 + }; + const int tab_D[] = + { 0xff, 0xfe, 0xfd, 0xfc, 10, -11, 11, -12, 8, 8, -9, -9, 9, 9, + -10, -10, 6, 6, 6, 6, -7, -7, -7, -7, 7, 7, 7, 7, -8, -8, + -8, -8, + 4, 4, 4, 4, + 4, 4, 4, 4, -5, -5, -5, -5, -5, -5, -5, -5, 5, 5, 5, 5, 5, + 5, 5, 5, + -6, -6, + -6, -6, -6, -6, -6, -6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, + 2, 2, -3, + -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, + 3, 3, + 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -4, -4, -4, -4, -4, -4, -4, + -4, -4, + -4, -4, -4, + -4, -4, -4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, + -1, -1, + -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, + 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, + -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, + -2, -2 + }; + + /* a_curve[19 + i] = ... [-19..19] => [-160..160] */ + const int a_curve[] = + { -160, -144, -128, -112, -98, -88, -80, -72, -64, -56, -48, + -40, -32, -24, -18, -12, -8, -5, -2, 0, 2, 5, 8, 12, 18, + 24, 32, + 40, 48, 56, 64, + 72, 80, 88, 98, 112, 128, 144, 160 + }; + /* clamp0_255[256 + i] = min(max(i,255),0) */ + const unsigned char clamp0_255[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, + 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, + 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, + 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, + 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, + 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, + 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, + 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, + 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, + 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, + 204, + 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, + 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, + 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + 255 + }; + /* abs_clamp15[19 + i] = min(abs(i), 15) */ + const int abs_clamp15[] = + { 15, 15, 15, 15, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, + 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 15, 15, + 15 + }; + /* diff_encoding[256 + i] = ... */ + const int diff_encoding[] = + { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, + 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5, + 5, 5, + 5, 5, 5, 5, 5, 3, 3, + 3, 3, 1, 1, 0, 2, 2, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, + 6, 6, 6, 6, 6, 6 + }; + + int block; + int bitfill = 0; + int xwidth = width + 6; + int off_up_right = 2 - 2 * xwidth; + int off_up_left = -2 - 2 * xwidth; + int pixel_U = 0, saved_pixel_UR = 0; + int pixel_x = 0, pixel_y = 2; + unsigned char *output_ptr = outbuf; + + memset(i_hits, 0, sizeof(i_hits)); + memset(accum, 0, sizeof(accum)); + + memcpy(outbuf + xwidth * 2 + 3, inbuf + 0x14, width); + memcpy(outbuf + xwidth * 3 + 3, inbuf + 0x14 + width, width); + + input_ptr = inbuf + 0x14 + width * 2; + output_ptr = outbuf + (xwidth) * 4 + 3; + + bit_bucket = 0; + + for (block = 0; block < ((height - 2) * width) / 32; ++block) { + int b_it, var_7 = 0; + int cur_byte; + + refill(&bitfill); + + cur_byte = (bit_bucket >> (bitfill & 7)) & 0xff; + + if ((cur_byte & 0x80) == 0) { + var_7 = 0; + bitfill--; + } else if ((cur_byte & 0xC0) == 0x80) { + var_7 = 1; + bitfill -= 2; + } else if ((cur_byte & 0xc0) == 0xc0) { + var_7 = 2; + bitfill -= 2; + } + + for (b_it = 0; b_it < 32; b_it++) { + int index; + int pixel_L, pixel_UR, pixel_UL; + int multiplier; + int dL, dC, dR; + int gkw; /* God knows what */ + + refill(&bitfill); + cur_byte = bit_bucket >> (bitfill & 7) & 0xff; + + pixel_L = output_ptr[-2]; + pixel_UR = output_ptr[off_up_right]; + pixel_UL = output_ptr[off_up_left]; + + dL = diff_encoding[0x100 + pixel_UL - pixel_L]; + dC = diff_encoding[0x100 + pixel_U - pixel_UL]; + dR = diff_encoding[0x100 + pixel_UR - pixel_U]; + + if (pixel_x < 2) { + pixel_L = pixel_UL = pixel_U = + output_ptr[-xwidth * 2]; + pixel_UR = output_ptr[off_up_right]; + dL = dC = 0; + dR = diff_encoding[0x100 + pixel_UR - + pixel_U]; + } else if (pixel_x > width - 3) + dR = 0; + + multiplier = 4; + index = dR + dC * 8 + dL * 64; + + if (pixel_L + pixel_U * 2 <= 144 + && (pixel_y & 1) == 0 + && (b_it & 3) == 0 && (dR < 5) && (dC < 5) + && (dL < 5)) { + multiplier = 1; + } else if (pixel_L <= 48 + && dL <= 4 && dC <= 4 && dL >= 1 + && dC >= 1) { + multiplier = 2; + } else if (var_7 == 1) { + multiplier = 2; + } else if (dC + dL >= 11 || var_7 == 2) { + multiplier = 8; + } + + if (i_hits[index] < 7) { + bitfill -= nbits_A[cur_byte]; + gkw = tab_A[cur_byte]; + if (gkw == 0xfe) + gkw = fun_A(&bitfill); + } else if (i_hits[index] >= accum[index]) { + bitfill -= nbits_B[cur_byte]; + gkw = tab_B[cur_byte]; + if (cur_byte == 0) + gkw = fun_B(&bitfill); + } else if (i_hits[index] * 2 >= accum[index]) { + bitfill -= nbits_C[cur_byte]; + gkw = tab_C[cur_byte]; + if (cur_byte < 2) + gkw = fun_C(&bitfill, gkw); + } else if (i_hits[index] * 4 >= accum[index]) { + bitfill -= nbits_D[cur_byte]; + gkw = tab_D[cur_byte]; + if (cur_byte < 4) + gkw = fun_D(&bitfill, gkw); + } else if (i_hits[index] * 8 >= accum[index]) { + gkw = fun_E(cur_byte, &bitfill); + } else { + gkw = fun_F(cur_byte, &bitfill); + } + + if (gkw == 0xff) + return -3; + + { + int tmp1, tmp2; + + tmp1 = + (pixel_U + pixel_L) * 3 - pixel_UL * 2; + tmp1 += (tmp1 < 0) ? 3 : 0; + tmp2 = a_curve[19 + gkw] * multiplier; + tmp2 += (tmp2 < 0) ? 1 : 0; + + *(output_ptr++) = + clamp0_255[0x100 + (tmp1 >> 2) - + (tmp2 >> 1)]; + } + pixel_U = saved_pixel_UR; + saved_pixel_UR = pixel_UR; + + if (++pixel_x == width) { + output_ptr += 6; + pixel_x = 0; + pixel_y++; + } + + accum[index] += abs_clamp15[19 + gkw]; + + if (i_hits[index]++ == 15) { + i_hits[index] = 8; + accum[index] /= 2; + } + } + } + return 0; +} + +/* FIXME, change spca561_decode not to need the extra border + around its dest buffer */ +int fswc_add_image_s561(avgbmp_t *dst, uint8_t *img, uint32_t length, uint32_t width, uint32_t height, int palette) +{ + uint x, y; + uint8_t *s, *d; + unsigned char tmpimg[650 * 490]; + + if(spca561_decode(width, height, img, tmpimg) != 0) + { + return(-1); + } + + /* Remove buffer border */ + d = tmpimg; + s = tmpimg + 2 * (width + 6) + 3; + for(y = 0; y < height; y++) + { + for(x = 0; x < width; x++) *(d++) = *(s++); + s += 6; + } + + fswc_add_image_bayer(dst, tmpimg, width * height, width, height, SRC_PAL_SGBRG8); + + return(0); +} + diff --git a/src/v4l/dec_yuv.c b/src/v4l/dec_yuv.c new file mode 100644 index 00000000..6336ce5e --- /dev/null +++ b/src/v4l/dec_yuv.c @@ -0,0 +1,170 @@ +/* fswebcam - Small and simple webcam for *nix */ +/*============================================================*/ +/* Copyright (C)2005-2010 Philip Heron */ +/* */ +/* This program is distributed under the terms of the GNU */ +/* General Public License, version 2. You may use, modify, */ +/* and redistribute it under the terms of this license. A */ +/* copy should be included with this source. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "src.h" + +/* The following YUV functions are based on code by Vincent Hourdin. + * http://vinvin.dyndns.org/projects/ + * + * Faster integer maths from camE by Tom Gilbert. + * http://linuxbrit.co.uk/camE/ +*/ + +int fswc_add_image_yuyv(src_t *src, avgbmp_t *abitmap) +{ + uint8_t *ptr; + uint32_t x, y, z; + + if(src->length < (src->width * src->height * 2)) return(-1); + + /* YUYV and UYVY are very similar and so * + * are both handled by this one function. */ + + ptr = (uint8_t *) src->img; + z = 0; + + for(y = 0; y < src->height; y++) + { + for(x = 0; x < src->width; x++) + { + int r, g, b; + int y, u, v; + + if(src->palette == SRC_PAL_UYVY) + { + if(!z) y = ptr[1] << 8; + else y = ptr[3] << 8; + + u = ptr[0] - 128; + v = ptr[2] - 128; + } + else /* SRC_PAL_YUYV */ + { + if(!z) y = ptr[0] << 8; + else y = ptr[2] << 8; + + u = ptr[1] - 128; + v = ptr[3] - 128; + } + + r = (y + (359 * v)) >> 8; + g = (y - (88 * u) - (183 * v)) >> 8; + b = (y + (454 * u)) >> 8; + + *(abitmap++) += CLIP(r, 0x00, 0xFF); + *(abitmap++) += CLIP(g, 0x00, 0xFF); + *(abitmap++) += CLIP(b, 0x00, 0xFF); + + if(z++) + { + z = 0; + ptr += 4; + } + } + } + + return(0); +} + +int fswc_add_image_yuv420p(src_t *src, avgbmp_t *abitmap) +{ + uint8_t *yptr, *uptr, *vptr; + uint32_t x, y, p, o; + + if(src->length < (src->width * src->height * 3) / 2) return(-1); + + /* Setup pointers to Y, U and V buffers. */ + yptr = (uint8_t *) src->img; + uptr = yptr + (src->width * src->height); + vptr = uptr + (src->width * src->height / 4); + o = 0; + p = 0; + + for(y = 0; y < src->height; y++) + { + for(x = 0; x < src->width; x++) + { + int r, g, b; + int y, u, v; + + y = *(yptr++) << 8; + u = uptr[p] - 128; + v = vptr[p] - 128; + + r = (y + (359 * v)) >> 8; + g = (y - (88 * u) - (183 * v)) >> 8; + b = (y + (454 * u)) >> 8; + + *(abitmap++) += CLIP(r, 0x00, 0xFF); + *(abitmap++) += CLIP(g, 0x00, 0xFF); + *(abitmap++) += CLIP(b, 0x00, 0xFF); + + if(x & 1) p++; + } + + if(!(y & 1)) p -= src->width / 2; + } + + return(0); +} + +int fswc_add_image_nv12mb(src_t *src, avgbmp_t *abitmap) +{ + uint32_t x, y; + uint32_t bw; + + if(src->length != (src->width * src->height * 3) / 2) return(-1); + + bw = src->width >> 4; + + for(y = 0; y < src->height; y++) + { + for(x = 0; x < src->width; x++) + { + uint32_t bx, by; + int cy, cu, cv; + int cr, cg, cb; + uint8_t *py, *puv; + + bx = x >> 4; + by = y >> 4; + + py = src->img; + py += ((by * bw) + bx) * 0x100; + py += ((y - (by << 4)) * 0x10) + (x - (bx << 4)); + + by /= 2; + + puv = (avgbmp_t *)src->img + (src->width * src->height); + puv += ((by * bw) + bx) * 0x100; + puv += (((y / 2) - (by << 4)) * 0x10) + ((x - (bx << 4)) &~ 1); + + cy = *py << 8; + cu = puv[0] - 128; + cv = puv[1] - 128; + + cr = (cy + (359 * cv)) >> 8; + cg = (cy - (88 * cu) - (183 * cv)) >> 8; + cb = (cy + (454 * cu)) >> 8; + + *(abitmap++) += CLIP(cr, 0x00, 0xFF); + *(abitmap++) += CLIP(cg, 0x00, 0xFF); + *(abitmap++) += CLIP(cb, 0x00, 0xFF); + } + } + + return(0); +} + diff --git a/src/v4l/src.c b/src/v4l/src.c index 391b121c..9cbc27fb 100644 --- a/src/v4l/src.c +++ b/src/v4l/src.c @@ -79,10 +79,10 @@ int src_open(src_t *src, char *source) return 0; } -const char *src_query(src_t *src, char *source, int *width, int *height, char **pixelformat) +const char *src_query(src_t *src, char *source, uint *width, uint *height, char **pixelformatdescription) { src->source = source; - return src_v4l2.query(src, width, height, pixelformat); + return src_v4l2.query(src, width, height, pixelformatdescription); } int src_close(src_t *src) diff --git a/src/v4l/src.h b/src/v4l/src.h index ae228a4b..3ce1d3b2 100644 --- a/src/v4l/src.h +++ b/src/v4l/src.h @@ -23,6 +23,11 @@ extern "C" { #ifndef INC_SRC_H #define INC_SRC_H +typedef unsigned char avgbmp_t; + + +#define CLIP(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val))) + #define SRC_TYPE_NONE (0) #define SRC_TYPE_DEVICE (1 << 0) /* Can capture from a device */ #define SRC_TYPE_FILE (1 << 1) /* Can capture from a file */ @@ -119,7 +124,7 @@ typedef struct { int (*open)(src_t *); int (*close)(src_t *); int (*grab)(src_t *); - const char *(*query)(src_t *, int*, int*, char **); + const char *(*query)(src_t *, uint*, uint*, char **); } src_mod_t; @@ -207,7 +212,7 @@ typedef struct { extern int src_open(src_t *src, char *source); extern int src_close(src_t *src); extern int src_grab(src_t *src); -extern const char *src_query(src_t *src, char *source, int *width, int *height, char **pixelformat); +extern const char *src_query(src_t *src, char *source, uint *width, uint *height, char **pixelformatdescription); extern int src_set_option(src_option_t ***options, char *name, char *value); extern int src_get_option_by_number(src_option_t **opt, int number, char **name, char **value); diff --git a/src/v4l/src_v4l2.c b/src/v4l/src_v4l2.c index 6c37abdf..7d1e03f4 100644 --- a/src/v4l/src_v4l2.c +++ b/src/v4l/src_v4l2.c @@ -802,7 +802,7 @@ int src_v4l2_set_read(src_t *src) return(0); } -static const char *src_v4l2_query(src_t *src, int *width, int *height, char **pixelformat) +static const char *src_v4l2_query(src_t *src, uint *width, uint *height, char **pixelformatdescription) { if(!src->source) { @@ -836,7 +836,8 @@ static const char *src_v4l2_query(src_t *src, int *width, int *height, char **pi fprintf(stderr, "Cannot get capabilities."); return NULL; } - char *res = (char*) s->cap.card; + char *res = strdup((char*) s->cap.card); + /*strcpy(res, (char*) s->cap.card);*/ if(!s->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { *width = 0; *height = 0; @@ -858,10 +859,13 @@ static const char *src_v4l2_query(src_t *src, int *width, int *height, char **pi fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(s->fd, VIDIOC_ENUM_FMT, &fmt) != -1) { - *pixelformat = fmt.description; + /*strcpy(*pixelformatdescription, (char *) fmt.description);*/ + *pixelformatdescription = strdup((char*)fmt.description); fprintf(stderr, "format: %s", fmt.description); } - else *pixelformat = ""; + else { + *pixelformatdescription = '\0'; + } } src_v4l2_close(src); return res; diff --git a/src/v4l/v4lcapture.cpp b/src/v4l/v4lcapture.cpp index c067a3a2..53ee5cf0 100644 --- a/src/v4l/v4lcapture.cpp +++ b/src/v4l/v4lcapture.cpp @@ -34,10 +34,30 @@ #include "v4lcapture.h" #include "kdenlivesettings.h" - +#include "dec.h" static src_t v4lsrc; +QImage add_image_png(src_t *src) +{ + QImage im; + im.loadFromData((uchar *)src->img, src->length, "PNG"); + return im; +} + +QImage add_image_jpeg(src_t *src) +{ + uint32_t hlength; + uint8_t *himg = NULL; + QImage im; + + /* MJPEG data may lack the DHT segment required for decoding... */ + verify_jpeg_dht((uint8_t *) src->img, src->length, &himg, &hlength); + + im.loadFromData(himg, hlength, "JPG"); + return im; +} + class MyDisplay : public QLabel { public: @@ -90,6 +110,9 @@ void MyDisplay::setImage(QImage img) V4lCaptureHandler::V4lCaptureHandler(QVBoxLayout *lay, QWidget *parent): CaptureHandler(lay, parent) , m_update(false) + , m_device(KdenliveSettings::video4vdevice()) + , m_width(-1) + , m_height(-1) { if (lay == NULL) return; m_display = new MyDisplay; @@ -122,8 +145,10 @@ QStringList V4lCaptureHandler::getDeviceName(QString input) config->delay = 0; config->use_read = 0; config->list = 0; - config->width = 384; - config->height = 288; + if (m_width > 0) config->width = m_width; + else config->width = 384; + if (m_height > 0) config->height = m_height; + else config->height = 288; config->fps = 0; config->frames = 1; config->skipframes = 0; @@ -154,15 +179,25 @@ QStringList V4lCaptureHandler::getDeviceName(QString input) v4lsrc.fps = config->fps; v4lsrc.option = config->option; char *source = config->device; - int width = 0; - int height = 0; - char *pixelformat; - QString deviceName = src_query(&v4lsrc, source, &width, &height, &pixelformat); + uint width = 0; + uint height = 0; + char *pixelformatdescription; + QString deviceName(src_query(&v4lsrc, source, &width, &height, &pixelformatdescription)); QStringList result; - result << (deviceName.isEmpty() ? input : deviceName) << (width == 0 ? QString() : QString("%1x%2").arg(width).arg(height)) << QString(pixelformat); + result << (deviceName.isEmpty() ? input : deviceName) << (width == 0 ? QString() : QString("%1x%2").arg(width).arg(height)) << QString(pixelformatdescription); return result; } +void V4lCaptureHandler::setDevice(const QString input, QString size) +{ + m_device = input; + if (!size.isEmpty()) { + m_width = size.section('x', 0, 0).toInt(); + m_height = size.section('x', -1).toInt(); + + } +} + void V4lCaptureHandler::startPreview(int /*deviceId*/, int /*captureMode*/, bool) { m_display->setHidden(false); @@ -183,15 +218,17 @@ void V4lCaptureHandler::startPreview(int /*deviceId*/, int /*captureMode*/, bool config->logfile = NULL; config->gmt = 0; config->start = 0; - config->device = strdup(KdenliveSettings::video4vdevice().toUtf8().constData()); + config->device = strdup(m_device.toUtf8().constData()); config->input = NULL; config->tuner = 0; config->frequency = 0; config->delay = 0; config->use_read = 0; config->list = 0; - config->width = KdenliveSettings::video4size().section("x", 0, 0).toInt();/*384;*/ - config->height = KdenliveSettings::video4size().section("x", -1).toInt();/*288;*/ + if (m_width > 0) config->width = m_width; + else config->width = KdenliveSettings::video4size().section("x", 0, 0).toInt();/*384;*/ + if (m_height > 0) config->height = m_height; + else config->height = KdenliveSettings::video4size().section("x", -1).toInt();/*288;*/ config->fps = 0; config->frames = 1; config->skipframes = 0; @@ -237,15 +274,59 @@ void V4lCaptureHandler::slotUpdate() { if (!m_update) return; src_grab(&v4lsrc); - uint8_t *img = (uint8_t *) v4lsrc.img; - uint32_t i = v4lsrc.width * v4lsrc.height; - - if (v4lsrc.length << 2 < i) return; + QImage qimg(v4lsrc.width, v4lsrc.height, QImage::Format_RGB888); + switch (v4lsrc.palette) { + case SRC_PAL_PNG: + qimg = add_image_png(&v4lsrc); + break; + case SRC_PAL_JPEG: + case SRC_PAL_MJPEG: + qimg = add_image_jpeg(&v4lsrc); + break; + case SRC_PAL_S561: + fswc_add_image_s561(qimg.bits(), (uchar *)v4lsrc.img, v4lsrc.length, v4lsrc.width, v4lsrc.height, v4lsrc.palette); + break; + case SRC_PAL_RGB32: + fswc_add_image_rgb32(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_BGR32: + fswc_add_image_bgr32(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_RGB24: + fswc_add_image_rgb24(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_BGR24: + fswc_add_image_bgr24(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_BAYER: + case SRC_PAL_SGBRG8: + case SRC_PAL_SGRBG8: + fswc_add_image_bayer(qimg.bits(), (uchar *)v4lsrc.img, v4lsrc.length, v4lsrc.width, v4lsrc.height, v4lsrc.palette); + break; + case SRC_PAL_YUYV: + case SRC_PAL_UYVY: + fswc_add_image_yuyv(&v4lsrc, (avgbmp_t *)qimg.bits()); + break; + case SRC_PAL_YUV420P: + fswc_add_image_yuv420p(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_NV12MB: + fswc_add_image_nv12mb(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_RGB565: + fswc_add_image_rgb565(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_RGB555: + fswc_add_image_rgb555(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_Y16: + fswc_add_image_y16(&v4lsrc, qimg.bits()); + break; + case SRC_PAL_GREY: + fswc_add_image_grey(&v4lsrc, qimg.bits()); + break; + } - QImage qimg(v4lsrc.width, v4lsrc.height, QImage::Format_RGB32); - //Format_ARGB32_Premultiplied - //convert from uyvy422 to rgba - CaptureHandler::yuv2rgb((uchar *)img, (uchar *)qimg.bits(), v4lsrc.width, v4lsrc.height); if (!m_captureFramePath.isEmpty()) { qimg.save(m_captureFramePath); emit frameSaved(m_captureFramePath); @@ -292,7 +373,10 @@ void V4lCaptureHandler::hidePreview(bool hide) void V4lCaptureHandler::stopPreview() { + m_display->setHidden(true); if (!m_update) return; m_update = false; src_close(&v4lsrc); } + + diff --git a/src/v4l/v4lcapture.h b/src/v4l/v4lcapture.h index 464bfa59..80ed0d4e 100644 --- a/src/v4l/v4lcapture.h +++ b/src/v4l/v4lcapture.h @@ -45,12 +45,17 @@ public: void hideOverlay(); void hidePreview(bool hide); QStringList getDeviceName(QString input); + /** @brief Sets the path to the capture devide and optionnaly the width / height of the capture. */ + void setDevice(const QString input, QString size = QString()); private: bool m_update; MyDisplay *m_display; QString m_captureFramePath; QImage m_overlayImage; + QString m_device; + int m_width; + int m_height; private slots: void slotUpdate(); -- 2.39.2