blob: 71291927fc903f32377d23d59656c44b312a6d06 [file] [log] [blame]
Constantin Kaplinsky0b263232007-08-02 13:51:09 +00001/* Copyright (C) 2007 Constantin Kaplinsky. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <rfb/JpegEncoder.h>
20#include <rdr/OutStream.h>
Constantin Kaplinsky651606d2007-10-17 17:40:23 +000021#include <rdr/Exception.h>
Constantin Kaplinsky0b263232007-08-02 13:51:09 +000022#include <rfb/encodings.h>
Constantin Kaplinsky651606d2007-10-17 17:40:23 +000023#include <rfb/ConnParams.h>
Constantin Kaplinsky48039462007-10-10 04:44:54 +000024#include <rfb/LogWriter.h>
Constantin Kaplinsky0b263232007-08-02 13:51:09 +000025
Constantin Kaplinsky51e66522007-12-19 06:25:06 +000026#ifdef HAVE_CL
27#include <rfb/IrixCLJpegCompressor.h>
28#endif
Constantin Kaplinskyd37420a2007-09-04 09:08:10 +000029#ifdef HAVE_DMEDIA
30#include <rfb/IrixDMJpegCompressor.h>
31#endif
32
Constantin Kaplinsky0b263232007-08-02 13:51:09 +000033using namespace rfb;
34
Constantin Kaplinsky48039462007-10-10 04:44:54 +000035static LogWriter vlog("JpegEncoder");
36
37BoolParameter JpegEncoder::useHardwareJPEG
38("UseHardwareJPEG",
39 "Use hardware-accelerated JPEG compressor for video if available",
40 true);
41
Constantin Kaplinsky0b263232007-08-02 13:51:09 +000042const int JpegEncoder::qualityMap[10] = {
Constantin Kaplinskyc2573702007-10-10 10:03:06 +000043 2, 10, 15, 25, 37, 50, 60, 70, 80, 90
Constantin Kaplinsky0b263232007-08-02 13:51:09 +000044};
45
Constantin Kaplinsky48039462007-10-10 04:44:54 +000046JpegEncoder::JpegEncoder(SMsgWriter* writer_) : writer(writer_), jcomp(0)
Constantin Kaplinsky0b263232007-08-02 13:51:09 +000047{
Constantin Kaplinsky1b738582007-12-20 15:30:20 +000048#ifdef HAVE_DMEDIA
49#ifdef DEBUG_FORCE_CL
50 vlog.debug("DEBUG: skipping IRIX DM JPEG compressor");
51#else
52 if (!jcomp && useHardwareJPEG) {
53 vlog.debug("trying IRIX DM JPEG compressor");
54 IrixDMJpegCompressor *dmComp = new IrixDMJpegCompressor;
55 if (dmComp->isValid()) {
56 vlog.debug("initialized IRIX DM JPEG compressor successfully");
57 jcomp = dmComp;
58 } else {
59 vlog.error("warning: could not create IRIX DM JPEG compressor");
60 delete dmComp;
61 }
62 }
63#endif
64#endif
65
Constantin Kaplinsky51e66522007-12-19 06:25:06 +000066#ifdef HAVE_CL
67 if (!jcomp && useHardwareJPEG) {
68 vlog.debug("trying IRIX CL JPEG compressor");
69 IrixCLJpegCompressor *clComp = new IrixCLJpegCompressor;
70 if (clComp->isValid()) {
71 vlog.debug("initialized IRIX CL JPEG compressor successfully");
72 jcomp = clComp;
Constantin Kaplinsky48039462007-10-10 04:44:54 +000073 } else {
Constantin Kaplinsky51e66522007-12-19 06:25:06 +000074 vlog.error("warning: could not create IRIX CL JPEG compressor");
75 delete clComp;
Constantin Kaplinsky48039462007-10-10 04:44:54 +000076 }
77 }
Constantin Kaplinsky51e66522007-12-19 06:25:06 +000078#endif
Constantin Kaplinsky1b738582007-12-20 15:30:20 +000079
Constantin Kaplinsky48039462007-10-10 04:44:54 +000080 if (!jcomp) {
Constantin Kaplinsky51e66522007-12-19 06:25:06 +000081 if (useHardwareJPEG) {
82 vlog.info("no hardware JPEG compressor available");
83 }
Constantin Kaplinsky48039462007-10-10 04:44:54 +000084 vlog.debug("using software JPEG compressor");
85 jcomp = new StandardJpegCompressor;
86 }
Constantin Kaplinsky0b263232007-08-02 13:51:09 +000087 jcomp->setQuality(qualityMap[6]);
88}
89
90JpegEncoder::~JpegEncoder()
91{
92 delete jcomp;
93}
94
95void JpegEncoder::setQualityLevel(int level)
96{
Constantin Kaplinskyc2573702007-10-10 10:03:06 +000097 if (level < 0) {
98 level = 0;
99 } else if (level > 9) {
100 level = 9;
Constantin Kaplinsky0b263232007-08-02 13:51:09 +0000101 }
Constantin Kaplinskyc2573702007-10-10 10:03:06 +0000102 jcomp->setQuality(qualityMap[level]);
Constantin Kaplinsky0b263232007-08-02 13:51:09 +0000103}
104
Constantin Kaplinsky651606d2007-10-17 17:40:23 +0000105bool JpegEncoder::isPixelFormatSupported(PixelBuffer* pb) const
Constantin Kaplinsky0b263232007-08-02 13:51:09 +0000106{
Constantin Kaplinsky651606d2007-10-17 17:40:23 +0000107 const PixelFormat &serverPF = pb->getPF();
108 const PixelFormat &clientPF = writer->getConnParams()->pf();
Constantin Kaplinsky0b263232007-08-02 13:51:09 +0000109
Constantin Kaplinsky651606d2007-10-17 17:40:23 +0000110 // FIXME: Ask encoders if they support given pixel formats.
111
112 if ( serverPF.bpp == 32 && clientPF.bpp >= 16 &&
113 serverPF.depth == 24 && serverPF.redMax == 255 &&
114 serverPF.greenMax == 255 && serverPF.blueMax == 255 ) {
115 return true;
116 }
117
118 return false;
119}
120
121void JpegEncoder::writeRect(PixelBuffer* pb, const Rect& r)
122{
123 if (!isPixelFormatSupported(pb)) {
124 vlog.error("pixel format unsupported by JPEG encoder");
125 throw rdr::Exception("internal error in JpegEncoder");
Constantin Kaplinsky0b263232007-08-02 13:51:09 +0000126 }
127
128 writer->startRect(r, encodingTight);
129 rdr::OutStream* os = writer->getOutStream();
130
131 // Get access to pixel data
132 int stride;
133 const rdr::U32* pixels = (const rdr::U32 *)pb->getPixelsR(r, &stride);
134 const PixelFormat& fmt = pb->getPF();
135
Constantin Kaplinsky67ebf002008-06-05 03:05:13 +0000136 // Try to encode data
Constantin Kaplinsky0b263232007-08-02 13:51:09 +0000137 jcomp->compress(pixels, &fmt, r.width(), r.height(), stride);
138
Constantin Kaplinsky67ebf002008-06-05 03:05:13 +0000139 // If not successful, switch to StandardJpegCompressor
140 if (jcomp->getDataLength() == 0) {
141 vlog.info("switching to standard software JPEG compressor");
142 delete jcomp;
143 jcomp = new StandardJpegCompressor;
144 jcomp->setQuality(qualityMap[6]);
Constantin Kaplinskye6658f92008-09-03 05:52:35 +0000145 jcomp->compress(pixels, &fmt, r.width(), r.height(), stride);
Constantin Kaplinsky67ebf002008-06-05 03:05:13 +0000146 }
147
Constantin Kaplinsky0b263232007-08-02 13:51:09 +0000148 // Write Tight-encoded header and JPEG data.
149 os->writeU8(0x09 << 4);
150 os->writeCompactLength(jcomp->getDataLength());
151 os->writeBytes(jcomp->getDataPtr(), jcomp->getDataLength());
152
153 writer->endRect();
Constantin Kaplinsky0b263232007-08-02 13:51:09 +0000154}
155