[libcamera-devel] qcam: Add JPEG format support

Message ID 20190329152705.29988-1-laurent.pinchart@ideasonboard.com
State Accepted
Commit 80e236e19b61a1267948433fd6855da138d6f527
Headers show
Series
  • [libcamera-devel] qcam: Add JPEG format support
Related show

Commit Message

Laurent Pinchart March 29, 2019, 3:27 p.m. UTC
When the camera provides MJPEG, use the QImage JPEG decompression code
to convert that to RGB.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/qcam/format_converter.cpp | 16 +++++++++++++++-
 src/qcam/format_converter.h   |  9 ++++++++-
 src/qcam/main_window.cpp      |  2 +-
 src/qcam/viewfinder.cpp       |  4 ++--
 src/qcam/viewfinder.h         |  2 +-
 5 files changed, 27 insertions(+), 6 deletions(-)

Comments

Kieran Bingham March 29, 2019, 3:39 p.m. UTC | #1
Hi Laurent,

Thank you for this - with a [small hack]* this brings me the ability to
view my UVC web camera using LibCamera and QCam on my laptop.

*small hack: UVC Pipeline handler requires updating to support MJPEG.

On 29/03/2019 15:27, Laurent Pinchart wrote:
> When the camera provides MJPEG, use the QImage JPEG decompression code
> to convert that to RGB.


Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  src/qcam/format_converter.cpp | 16 +++++++++++++++-
>  src/qcam/format_converter.h   |  9 ++++++++-
>  src/qcam/main_window.cpp      |  2 +-
>  src/qcam/viewfinder.cpp       |  4 ++--
>  src/qcam/viewfinder.h         |  2 +-
>  5 files changed, 27 insertions(+), 6 deletions(-)
> 
> diff --git a/src/qcam/format_converter.cpp b/src/qcam/format_converter.cpp
> index 6979a054c0ca..bda9057e17b6 100644
> --- a/src/qcam/format_converter.cpp
> +++ b/src/qcam/format_converter.cpp
> @@ -9,6 +9,8 @@
>  
>  #include <linux/videodev2.h>
>  
> +#include <QImage>
> +
>  #include "format_converter.h"
>  
>  #define RGBSHIFT		8
> @@ -45,16 +47,28 @@ int FormatConverter::configure(unsigned int format, unsigned int width,
>  		y_pos_ = 0;
>  		cb_pos_ = 1;
>  		break;
> +	case V4L2_PIX_FMT_MJPEG:
> +		break;
>  	default:
>  		return -EINVAL;
>  	};
>  
> +	format_ = format;
>  	width_ = width;
>  	height_ = height;
>  
>  	return 0;
>  }
>  
> +void FormatConverter::convert(const unsigned char *src, size_t size,
> +			      QImage *dst)
> +{
> +	if (format_ == V4L2_PIX_FMT_MJPEG)
> +		dst->loadFromData(src, size, "JPEG");
> +	else
> +		convertYUV(src, dst->bits());
> +}
> +
>  static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
>  {
>  	int c = y - 16;
> @@ -65,7 +79,7 @@ static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
>  	*b = CLIP(( 298 * c + 516 * d           + 128) >> RGBSHIFT);
>  }
>  
> -void FormatConverter::convert(const unsigned char *src, unsigned char *dst)
> +void FormatConverter::convertYUV(const unsigned char *src, unsigned char *dst)
>  {
>  	unsigned int src_x, src_y, dst_x, dst_y;
>  	unsigned int src_stride;
> diff --git a/src/qcam/format_converter.h b/src/qcam/format_converter.h
> index 196064c74f65..396d0bea116a 100644
> --- a/src/qcam/format_converter.h
> +++ b/src/qcam/format_converter.h
> @@ -7,15 +7,22 @@
>  #ifndef __QCAM_FORMAT_CONVERTER_H__
>  #define __QCAM_FORMAT_CONVERTER_H__
>  
> +#include <stddef.h>
> +
> +class QImage;
> +
>  class FormatConverter
>  {
>  public:
>  	int configure(unsigned int format, unsigned int width,
>  		      unsigned int height);
>  
> -	void convert(const unsigned char *src, unsigned char *dst);
> +	void convert(const unsigned char *src, size_t size, QImage *dst);
>  
>  private:
> +	void convertYUV(const unsigned char *src, unsigned char *dst);
> +
> +	unsigned int format_;
>  	unsigned int width_;
>  	unsigned int height_;
>  	unsigned int y_pos_;
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index a148aa4d117f..fea701422015 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -222,7 +222,7 @@ int MainWindow::display(Buffer *buffer)
>  
>  	Plane &plane = buffer->planes().front();
>  	unsigned char *raw = static_cast<unsigned char *>(plane.mem());
> -	viewfinder_->display(raw);
> +	viewfinder_->display(raw, buffer->bytesused());
>  
>  	return 0;
>  }
> diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp
> index 5841dc032967..224a227ddd5b 100644
> --- a/src/qcam/viewfinder.cpp
> +++ b/src/qcam/viewfinder.cpp
> @@ -16,9 +16,9 @@ ViewFinder::ViewFinder(QWidget *parent)
>  {
>  }
>  
> -void ViewFinder::display(const unsigned char *raw)
> +void ViewFinder::display(const unsigned char *raw, size_t size)
>  {
> -	converter_.convert(raw, image_->bits());
> +	converter_.convert(raw, size, image_);
>  
>  	QPixmap pixmap = QPixmap::fromImage(*image_);
>  	setPixmap(pixmap);
> diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h
> index df4901699a14..c9ca98913e05 100644
> --- a/src/qcam/viewfinder.h
> +++ b/src/qcam/viewfinder.h
> @@ -20,7 +20,7 @@ public:
>  
>  	int setFormat(unsigned int format, unsigned int width,
>  		      unsigned int height);
> -	void display(const unsigned char *rgb);
> +	void display(const unsigned char *rgb, size_t size);
>  
>  private:
>  	unsigned int format_;
>
Niklas Söderlund March 29, 2019, 5:18 p.m. UTC | #2
Hi Laurent,

Thanks for your work.

On 2019-03-29 17:27:05 +0200, Laurent Pinchart wrote:
> When the camera provides MJPEG, use the QImage JPEG decompression code
> to convert that to RGB.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>

> ---
>  src/qcam/format_converter.cpp | 16 +++++++++++++++-
>  src/qcam/format_converter.h   |  9 ++++++++-
>  src/qcam/main_window.cpp      |  2 +-
>  src/qcam/viewfinder.cpp       |  4 ++--
>  src/qcam/viewfinder.h         |  2 +-
>  5 files changed, 27 insertions(+), 6 deletions(-)
> 
> diff --git a/src/qcam/format_converter.cpp b/src/qcam/format_converter.cpp
> index 6979a054c0ca..bda9057e17b6 100644
> --- a/src/qcam/format_converter.cpp
> +++ b/src/qcam/format_converter.cpp
> @@ -9,6 +9,8 @@
>  
>  #include <linux/videodev2.h>
>  
> +#include <QImage>
> +
>  #include "format_converter.h"
>  
>  #define RGBSHIFT		8
> @@ -45,16 +47,28 @@ int FormatConverter::configure(unsigned int format, unsigned int width,
>  		y_pos_ = 0;
>  		cb_pos_ = 1;
>  		break;
> +	case V4L2_PIX_FMT_MJPEG:
> +		break;
>  	default:
>  		return -EINVAL;
>  	};
>  
> +	format_ = format;
>  	width_ = width;
>  	height_ = height;
>  
>  	return 0;
>  }
>  
> +void FormatConverter::convert(const unsigned char *src, size_t size,
> +			      QImage *dst)
> +{
> +	if (format_ == V4L2_PIX_FMT_MJPEG)
> +		dst->loadFromData(src, size, "JPEG");
> +	else
> +		convertYUV(src, dst->bits());
> +}
> +
>  static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
>  {
>  	int c = y - 16;
> @@ -65,7 +79,7 @@ static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
>  	*b = CLIP(( 298 * c + 516 * d           + 128) >> RGBSHIFT);
>  }
>  
> -void FormatConverter::convert(const unsigned char *src, unsigned char *dst)
> +void FormatConverter::convertYUV(const unsigned char *src, unsigned char *dst)
>  {
>  	unsigned int src_x, src_y, dst_x, dst_y;
>  	unsigned int src_stride;
> diff --git a/src/qcam/format_converter.h b/src/qcam/format_converter.h
> index 196064c74f65..396d0bea116a 100644
> --- a/src/qcam/format_converter.h
> +++ b/src/qcam/format_converter.h
> @@ -7,15 +7,22 @@
>  #ifndef __QCAM_FORMAT_CONVERTER_H__
>  #define __QCAM_FORMAT_CONVERTER_H__
>  
> +#include <stddef.h>
> +
> +class QImage;
> +
>  class FormatConverter
>  {
>  public:
>  	int configure(unsigned int format, unsigned int width,
>  		      unsigned int height);
>  
> -	void convert(const unsigned char *src, unsigned char *dst);
> +	void convert(const unsigned char *src, size_t size, QImage *dst);
>  
>  private:
> +	void convertYUV(const unsigned char *src, unsigned char *dst);
> +
> +	unsigned int format_;
>  	unsigned int width_;
>  	unsigned int height_;
>  	unsigned int y_pos_;
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index a148aa4d117f..fea701422015 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -222,7 +222,7 @@ int MainWindow::display(Buffer *buffer)
>  
>  	Plane &plane = buffer->planes().front();
>  	unsigned char *raw = static_cast<unsigned char *>(plane.mem());
> -	viewfinder_->display(raw);
> +	viewfinder_->display(raw, buffer->bytesused());
>  
>  	return 0;
>  }
> diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp
> index 5841dc032967..224a227ddd5b 100644
> --- a/src/qcam/viewfinder.cpp
> +++ b/src/qcam/viewfinder.cpp
> @@ -16,9 +16,9 @@ ViewFinder::ViewFinder(QWidget *parent)
>  {
>  }
>  
> -void ViewFinder::display(const unsigned char *raw)
> +void ViewFinder::display(const unsigned char *raw, size_t size)
>  {
> -	converter_.convert(raw, image_->bits());
> +	converter_.convert(raw, size, image_);
>  
>  	QPixmap pixmap = QPixmap::fromImage(*image_);
>  	setPixmap(pixmap);
> diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h
> index df4901699a14..c9ca98913e05 100644
> --- a/src/qcam/viewfinder.h
> +++ b/src/qcam/viewfinder.h
> @@ -20,7 +20,7 @@ public:
>  
>  	int setFormat(unsigned int format, unsigned int width,
>  		      unsigned int height);
> -	void display(const unsigned char *rgb);
> +	void display(const unsigned char *rgb, size_t size);
>  
>  private:
>  	unsigned int format_;
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

Patch

diff --git a/src/qcam/format_converter.cpp b/src/qcam/format_converter.cpp
index 6979a054c0ca..bda9057e17b6 100644
--- a/src/qcam/format_converter.cpp
+++ b/src/qcam/format_converter.cpp
@@ -9,6 +9,8 @@ 
 
 #include <linux/videodev2.h>
 
+#include <QImage>
+
 #include "format_converter.h"
 
 #define RGBSHIFT		8
@@ -45,16 +47,28 @@  int FormatConverter::configure(unsigned int format, unsigned int width,
 		y_pos_ = 0;
 		cb_pos_ = 1;
 		break;
+	case V4L2_PIX_FMT_MJPEG:
+		break;
 	default:
 		return -EINVAL;
 	};
 
+	format_ = format;
 	width_ = width;
 	height_ = height;
 
 	return 0;
 }
 
+void FormatConverter::convert(const unsigned char *src, size_t size,
+			      QImage *dst)
+{
+	if (format_ == V4L2_PIX_FMT_MJPEG)
+		dst->loadFromData(src, size, "JPEG");
+	else
+		convertYUV(src, dst->bits());
+}
+
 static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
 {
 	int c = y - 16;
@@ -65,7 +79,7 @@  static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
 	*b = CLIP(( 298 * c + 516 * d           + 128) >> RGBSHIFT);
 }
 
-void FormatConverter::convert(const unsigned char *src, unsigned char *dst)
+void FormatConverter::convertYUV(const unsigned char *src, unsigned char *dst)
 {
 	unsigned int src_x, src_y, dst_x, dst_y;
 	unsigned int src_stride;
diff --git a/src/qcam/format_converter.h b/src/qcam/format_converter.h
index 196064c74f65..396d0bea116a 100644
--- a/src/qcam/format_converter.h
+++ b/src/qcam/format_converter.h
@@ -7,15 +7,22 @@ 
 #ifndef __QCAM_FORMAT_CONVERTER_H__
 #define __QCAM_FORMAT_CONVERTER_H__
 
+#include <stddef.h>
+
+class QImage;
+
 class FormatConverter
 {
 public:
 	int configure(unsigned int format, unsigned int width,
 		      unsigned int height);
 
-	void convert(const unsigned char *src, unsigned char *dst);
+	void convert(const unsigned char *src, size_t size, QImage *dst);
 
 private:
+	void convertYUV(const unsigned char *src, unsigned char *dst);
+
+	unsigned int format_;
 	unsigned int width_;
 	unsigned int height_;
 	unsigned int y_pos_;
diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index a148aa4d117f..fea701422015 100644
--- a/src/qcam/main_window.cpp
+++ b/src/qcam/main_window.cpp
@@ -222,7 +222,7 @@  int MainWindow::display(Buffer *buffer)
 
 	Plane &plane = buffer->planes().front();
 	unsigned char *raw = static_cast<unsigned char *>(plane.mem());
-	viewfinder_->display(raw);
+	viewfinder_->display(raw, buffer->bytesused());
 
 	return 0;
 }
diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp
index 5841dc032967..224a227ddd5b 100644
--- a/src/qcam/viewfinder.cpp
+++ b/src/qcam/viewfinder.cpp
@@ -16,9 +16,9 @@  ViewFinder::ViewFinder(QWidget *parent)
 {
 }
 
-void ViewFinder::display(const unsigned char *raw)
+void ViewFinder::display(const unsigned char *raw, size_t size)
 {
-	converter_.convert(raw, image_->bits());
+	converter_.convert(raw, size, image_);
 
 	QPixmap pixmap = QPixmap::fromImage(*image_);
 	setPixmap(pixmap);
diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h
index df4901699a14..c9ca98913e05 100644
--- a/src/qcam/viewfinder.h
+++ b/src/qcam/viewfinder.h
@@ -20,7 +20,7 @@  public:
 
 	int setFormat(unsigned int format, unsigned int width,
 		      unsigned int height);
-	void display(const unsigned char *rgb);
+	void display(const unsigned char *rgb, size_t size);
 
 private:
 	unsigned int format_;