Mbed OS version of IoT.js implementation running on GR-PEACH

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers iotjs_module_jpeg.c Source File

iotjs_module_jpeg.c

00001 /* Copyright 2017-present Renesas Electronics Corporation and other contributors
00002  *
00003  * Licensed under the Apache License, Version 2.0 (the "License");
00004  * you may not use this file except in compliance with the License.
00005  * You may obtain a copy of the License at
00006  *
00007  *     http://www.apache.org/licenses/LICENSE-2.0
00008  *
00009  * Unless required by applicable law or agreed to in writing, software
00010  * distributed under the License is distributed on an "AS IS" BASIS
00011  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012  * See the License for the specific language governing permissions and
00013  * limitations under the License.
00014  */
00015 
00016 #include "iotjs_def.h"
00017 
00018 #if defined(USE_POSIX_BRIDGE)
00019 #include "peripheral_io.h"
00020 #include "iotjs_module_aligned_buffer.h"
00021 #include "iotjs_module_jpeg.h"
00022 #include <malloc.h>
00023 
00024 IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(jpeg);
00025 
00026 struct iotjs_jpeg_platform_data_s {
00027   int dummy;
00028 };
00029 
00030 jerry_value_t iotjs_jpeg_set_platform_config(iotjs_jpeg_t* jpeg,
00031                                              const jerry_value_t jconfig) {
00032   return jerry_create_undefined();
00033 }
00034 
00035 void iotjs_jpeg_create_platform_data(iotjs_jpeg_t* jpeg) {
00036   jpeg->platform_data = IOTJS_ALLOC(iotjs_jpeg_platform_data_t);
00037 }
00038 
00039 void iotjs_jpeg_destroy_platform_data(
00040     iotjs_jpeg_platform_data_t* platform_data) {
00041   IOTJS_RELEASE(platform_data);
00042 }
00043 
00044 IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(jpeg);
00045 
00046 static uint32_t get_pixel_bytes(jpeg_pixel_format_t format) {
00047     switch(format) {
00048     case JPEG_PIXELFORMAT_YCBCR422:
00049     case JPEG_PIXELFORMAT_RGB565:
00050         return 2;
00051     case JPEG_PIXELFORMAT_ARGB8888:
00052         return 4;
00053     default:
00054         return 0;
00055     }
00056 }
00057 
00058 bool iotjs_jpeg_encode(iotjs_jpeg_t* jpeg) {
00059   uint32_t width = (jpeg->encode_data.width + 31)&~31;
00060   uint32_t height = (jpeg->encode_data.height + 15)&~15;
00061   uint32_t encode_len = width * height * get_pixel_bytes(jpeg->encode_data.pixel_format);
00062   jpeg->encode_data.dst.buf = memalign(32, encode_len);
00063   if(jpeg->encode_data.dst.buf == NULL) {
00064     return false;
00065   }
00066   jpeg->encode_data.src.len = encode_len;
00067   jpeg->encode_data.dst.len = encode_len;
00068 
00069   int ret = jpeg_encode(jpeg->encode_data);
00070   if(ret < 0) {
00071     IOTJS_RELEASE(jpeg->encode_data.dst.buf);
00072     return false;
00073   }
00074 
00075   jpeg->encode_data.dst.len = ret;
00076 
00077   return true;
00078 }
00079 
00080 bool iotjs_jpeg_decode(iotjs_jpeg_t* jpeg) {
00081   uint32_t width = (jpeg->decode_data.width + 31)&~31;
00082   uint32_t height = (jpeg->decode_data.height + 15)&~15;
00083   uint32_t decode_len = width * height * get_pixel_bytes(jpeg->decode_data.pixel_format);
00084   jpeg->decode_data.dst.buf = memalign(32, decode_len);
00085   if(jpeg->decode_data.dst.buf == NULL) {
00086     return false;
00087   }
00088   memset(jpeg->decode_data.dst.buf, 0, decode_len);
00089   jpeg->decode_data.dst.len = decode_len;
00090 
00091   bool ret = jpeg_decode(jpeg->decode_data);
00092   if(!ret) {
00093     IOTJS_RELEASE(jpeg->decode_data.dst.buf);
00094     return false;
00095   }
00096 
00097   return true;
00098 }
00099 
00100 static void iotjs_jpeg_destroy(iotjs_jpeg_t* jpeg) {
00101   iotjs_jpeg_destroy_platform_data(jpeg->platform_data);
00102   IOTJS_RELEASE(jpeg);
00103 }
00104 
00105 static void jpeg_worker(uv_work_t* work_req) {
00106   iotjs_periph_reqwrap_t* req_wrap =
00107       (iotjs_periph_reqwrap_t*)(iotjs_reqwrap_from_request(
00108           (uv_req_t*)work_req));
00109   iotjs_jpeg_t* jpeg = (iotjs_jpeg_t*)req_wrap->data;
00110 
00111   switch (req_wrap->op) {
00112     case kJpegOpEncode:
00113       req_wrap->result = iotjs_jpeg_encode(jpeg);
00114       break;
00115     case kJpegOpDecode:
00116       req_wrap->result = iotjs_jpeg_decode(jpeg);
00117       break;
00118     default:
00119       IOTJS_ASSERT(!"Invalid Operation");
00120   }
00121 }
00122 
00123 static jerry_value_t jpeg_set_configuration(iotjs_jpeg_t* jpeg,
00124                                             jerry_value_t jconfig) {
00125   return jerry_create_undefined();
00126 }
00127 
00128 
00129 static jerry_value_t jpeg_get_encode_param(iotjs_jpeg_t* jpeg,
00130                                             const jerry_value_t jargv[],
00131                                             const jerry_length_t jargc) {
00132   if(jargc < 1) {
00133     return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
00134   }
00135 
00136   jerry_value_t jimage = JS_GET_ARG(0, object);
00137   jerry_value_t jwidth = iotjs_jval_get_property(jimage, "width");
00138   if (jerry_value_is_number(jwidth)) {
00139     jpeg->encode_data.width = iotjs_jval_as_number(jwidth);
00140   } else {
00141     jerry_release_value(jwidth);
00142     return JS_CREATE_ERROR(
00143         TYPE, "Invalid image.width");
00144   }
00145   jerry_release_value(jwidth);
00146 
00147   jerry_value_t jheight = iotjs_jval_get_property(jimage, "height");
00148   if (jerry_value_is_number(jheight)) {
00149     jpeg->encode_data.height = iotjs_jval_as_number(jheight);
00150   } else {
00151     jerry_release_value(jheight);
00152     return JS_CREATE_ERROR(
00153         TYPE, "Invalid image.height");
00154   }
00155   jerry_release_value(jheight);
00156 
00157   jerry_value_t jformat = iotjs_jval_get_property(jimage, "format");
00158   if (jerry_value_is_number(jformat)) {
00159     jpeg->encode_data.pixel_format = iotjs_jval_as_number(jformat);
00160   } else {
00161     jpeg->encode_data.pixel_format = JPEG_PIXELFORMAT_MAX;
00162   }
00163   jerry_release_value(jformat);
00164   if(jpeg->encode_data.pixel_format != JPEG_PIXELFORMAT_YCBCR422) {
00165     return JS_CREATE_ERROR(TYPE, "Invalid image.format");
00166   }
00167 
00168   jerry_value_t jbitmap = iotjs_jval_get_property(jimage, "bitmap");
00169   iotjs_aligned_buffer_wrap_t* buffer_wrap = iotjs_aligned_buffer_wrap_from_jbuffer(jbitmap);
00170   jpeg->encode_data.src.buf = (uint8_t*)iotjs_aligned_buffer_wrap_native_buffer_ptr(buffer_wrap);
00171   jerry_release_value(jbitmap);
00172   if(((buffer_wrap->alignment % 32) != 0) || (((int)jpeg->encode_data.src.buf % 32) != 0)) {
00173     return JS_CREATE_ERROR(TYPE, "Invalid image.bitmap alignment");
00174   }
00175 
00176   return jerry_create_undefined();
00177 }
00178 
00179 
00180 static jerry_value_t jpeg_get_decode_param(iotjs_jpeg_t* jpeg,
00181                                             const jerry_value_t jargv[],
00182                                             const jerry_length_t jargc) {
00183   if(jargc < 2) {
00184     return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
00185   }
00186 
00187   const jerry_value_t jjpeg_data = JS_GET_ARG(0, object);
00188   iotjs_aligned_buffer_wrap_t* buffer_wrap = iotjs_aligned_buffer_wrap_from_jbuffer(jjpeg_data);
00189   jpeg->decode_data.src.buf = iotjs_aligned_buffer_wrap_native_buffer_ptr(buffer_wrap);
00190   jpeg->decode_data.src.len = buffer_wrap->length;
00191   if(((buffer_wrap->alignment % 32) != 0) || (((int)jpeg->decode_data.src.buf % 32) != 0)) {
00192     return JS_CREATE_ERROR(TYPE, "Invalid jpegData alignment");
00193   }
00194 
00195   const jerry_value_t jconfig = JS_GET_ARG(1, object);
00196 
00197   jerry_value_t jwidth = iotjs_jval_get_property(jconfig, "width");
00198   if (jerry_value_is_number(jwidth)) {
00199     jpeg->decode_data.width = iotjs_jval_as_number(jwidth);
00200   } else {
00201     jerry_release_value(jwidth);
00202     return JS_CREATE_ERROR(
00203         TYPE, "Invalid options.width");
00204   }
00205   jerry_release_value(jwidth);
00206 
00207   jerry_value_t jheight = iotjs_jval_get_property(jconfig, "height");
00208   if (jerry_value_is_number(jheight)) {
00209     jpeg->decode_data.height = iotjs_jval_as_number(jheight);
00210   } else {
00211     jerry_release_value(jheight);
00212     return JS_CREATE_ERROR(
00213         TYPE, "Invalid options.height");
00214   }
00215   jerry_release_value(jheight);
00216 
00217   jerry_value_t jformat = iotjs_jval_get_property(jconfig, "format");
00218   if (jerry_value_is_number(jformat)) {
00219     jpeg->decode_data.pixel_format = iotjs_jval_as_number(jformat);
00220   } else {
00221     jpeg->decode_data.pixel_format = JPEG_PIXELFORMAT_MAX;
00222   }
00223   jerry_release_value(jformat);
00224   if(jpeg->decode_data.pixel_format >= JPEG_PIXELFORMAT_MAX) {
00225     return JS_CREATE_ERROR(TYPE, "Invalid options.format");
00226   }
00227 
00228   if(jpeg->decode_data.pixel_format == JPEG_PIXELFORMAT_ARGB8888) {
00229     jerry_value_t jalpha = iotjs_jval_get_property(jconfig, "alpha");
00230     if (jerry_value_is_undefined(jalpha)) {
00231       jpeg->decode_data.alpha = 0xFF;
00232     } else {
00233       if (jerry_value_is_number(jalpha)) {
00234         jpeg->decode_data.alpha = iotjs_jval_as_number(jalpha);
00235       } else {
00236         jerry_release_value(jalpha);
00237         return JS_CREATE_ERROR(TYPE, "Invalid options.alpha");
00238       }
00239     }
00240     jerry_release_value(jalpha);
00241   } else {
00242     jpeg->decode_data.alpha = 0;
00243   }
00244 
00245   return jerry_create_undefined();
00246 }
00247 
00248 JS_FUNCTION(JpegCons) {
00249   DJS_CHECK_THIS();
00250 
00251   // Create Jpeg object
00252   jerry_value_t jjpeg = JS_GET_THIS();
00253   iotjs_jpeg_t* jpeg = jpeg_create(jjpeg);
00254 
00255   jerry_value_t jconfig = JS_GET_ARG(0, object);
00256 
00257   // set configuration
00258   jerry_value_t res = iotjs_jpeg_set_platform_config(jpeg, jconfig);
00259   if (jerry_value_is_error(res)) {
00260     return res;
00261   }
00262 
00263   res = jpeg_set_configuration(jpeg, jconfig);
00264   if (jerry_value_is_error(res)) {
00265     return res;
00266   }
00267 
00268   return jerry_create_undefined();
00269 }
00270 
00271 
00272 JS_FUNCTION(Encode) {
00273   JS_DECLARE_THIS_PTR(jpeg, jpeg);
00274   DJS_CHECK_ARGS(1, object);
00275 
00276   jerry_value_t jerr = jpeg_get_encode_param(jpeg, jargv, jargc);
00277   if(jerry_value_is_error(jerr)) {
00278     return jerr;
00279   }
00280   iotjs_ext_periph_call_async(jpeg, JS_GET_ARG_IF_EXIST(1, function), kJpegOpEncode,
00281                           jpeg_worker);
00282   return jerry_create_undefined();
00283 }
00284 
00285 
00286 JS_FUNCTION(EncodeSync) {
00287   JS_DECLARE_THIS_PTR(jpeg, jpeg);
00288   DJS_CHECK_ARGS(1, object);
00289 
00290   jerry_value_t jerr = jpeg_get_encode_param(jpeg, jargv, jargc);
00291   if(jerry_value_is_error(jerr)) {
00292     return jerr;
00293   }
00294 
00295   if(!iotjs_jpeg_encode(jpeg)) {
00296     return JS_CREATE_ERROR(COMMON, "Encode error, cannot encode Jpeg");
00297   }
00298 
00299   jerry_value_t jbuf = iotjs_aligned_buffer_wrap_create_buffer((size_t)jpeg->encode_data.dst.len, 32);
00300   if (jerry_value_is_error(jbuf)) {
00301     IOTJS_RELEASE(jpeg->encode_data.dst.buf);
00302     return jbuf;
00303   }
00304 
00305   iotjs_aligned_buffer_wrap_t* buf_wrap = iotjs_aligned_buffer_wrap_from_jbuffer(jbuf);
00306   iotjs_aligned_buffer_wrap_copy(buf_wrap, jpeg->encode_data.dst.buf, jpeg->encode_data.dst.len);
00307   IOTJS_RELEASE(jpeg->encode_data.dst.buf);
00308 
00309   return jbuf;
00310 }
00311 
00312 
00313 JS_FUNCTION(Decode) {
00314   JS_DECLARE_THIS_PTR(jpeg, jpeg);
00315   DJS_CHECK_ARGS(2, object, object);
00316 
00317   jerry_value_t res = jpeg_get_decode_param(jpeg, jargv, jargc);
00318   if (jerry_value_is_error(res)) {
00319     return res;
00320   }
00321 
00322   iotjs_ext_periph_call_async(jpeg, JS_GET_ARG_IF_EXIST(2, function), kJpegOpDecode,
00323                           jpeg_worker);
00324   return jerry_create_undefined();
00325 }
00326 
00327 
00328 JS_FUNCTION(DecodeSync) {
00329   JS_DECLARE_THIS_PTR(jpeg, jpeg);
00330   DJS_CHECK_ARGS(2, object, object);
00331 
00332   jerry_value_t res = jpeg_get_decode_param(jpeg, jargv, jargc);
00333   if (jerry_value_is_error(res)) {
00334     return res;
00335   }
00336 
00337   if(!iotjs_jpeg_decode(jpeg)) {
00338     return JS_CREATE_ERROR(COMMON, "Decode error, cannot decode Jpeg");
00339   }
00340 
00341   jerry_value_t jbuf = iotjs_aligned_buffer_wrap_create_buffer((size_t)jpeg->decode_data.dst.len, 32);
00342   if (jerry_value_is_error(jbuf)) {
00343     IOTJS_RELEASE(jpeg->decode_data.dst.buf);
00344     return jbuf;
00345   }
00346 
00347   iotjs_aligned_buffer_wrap_t* buf_wrap = iotjs_aligned_buffer_wrap_from_jbuffer(jbuf);
00348   iotjs_aligned_buffer_wrap_copy(buf_wrap, jpeg->decode_data.dst.buf, jpeg->decode_data.dst.len);
00349   IOTJS_RELEASE(jpeg->decode_data.dst.buf);
00350 
00351   return jbuf;
00352 }
00353 
00354 #endif  // #if defined(USE_POSIX_BRIDGE)
00355 
00356 
00357 jerry_value_t InitJpeg() {
00358 
00359 #if defined(USE_POSIX_BRIDGE)
00360   jerry_value_t jjpeg_cons = jerry_create_external_function(JpegCons);
00361 
00362   jerry_value_t prototype = jerry_create_object();
00363   iotjs_jval_set_method(prototype, "encode", Encode);
00364   iotjs_jval_set_method(prototype, "encodeSync", EncodeSync);
00365   iotjs_jval_set_method(prototype, "decode", Decode);
00366   iotjs_jval_set_method(prototype, "decodeSync", DecodeSync);
00367 
00368   // JPEG Pixel Format
00369   jerry_value_t jformat = jerry_create_object();
00370   iotjs_jval_set_property_number(jformat, "YCBCR422", JPEG_PIXELFORMAT_YCBCR422);
00371   iotjs_jval_set_property_number(jformat, "ARGB8888", JPEG_PIXELFORMAT_ARGB8888);
00372   iotjs_jval_set_property_number(jformat, "RGB565", JPEG_PIXELFORMAT_RGB565);
00373   iotjs_jval_set_property_number(jformat, "MAX", JPEG_PIXELFORMAT_MAX);
00374   iotjs_jval_set_property_jval(prototype, "PIXELFORMAT", jformat);
00375   jerry_release_value(jformat);
00376 
00377   iotjs_jval_set_property_jval(jjpeg_cons, IOTJS_MAGIC_STRING_PROTOTYPE,
00378                                prototype);
00379   jerry_release_value(prototype);
00380 
00381 #else   // #if defined(USE_POSIX_BRIDGE)
00382   jerry_value_t jjpeg_cons = jerry_create_object();
00383 #endif  // #if defined(USE_POSIX_BRIDGE)
00384 
00385   return jjpeg_cons;
00386 }