A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 888 lines 30 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2008 by Akio Idehara, Andrew Mahone 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22/* 23 * Implementation of area average and linear row and vertical scalers, and 24 * nearest-neighbor grey scaler (C) 2008 Andrew Mahone 25 * 26 * All files in this archive are subject to the GNU General Public License. 27 * See the file COPYING in the source tree root for full license agreement. 28 * 29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 30 * KIND, either express or implied. 31 * 32 ****************************************************************************/ 33 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <stdint.h> 38 39#include "general.h" 40#include "kernel.h" 41#include "system.h" 42#ifndef PLUGIN 43#include "debug.h" 44#endif 45#include "lcd.h" 46#include "file.h" 47#ifdef HAVE_REMOTE_LCD 48#include "lcd-remote.h" 49#endif 50#ifdef ROCKBOX_DEBUG_SCALERS 51#define SDEBUGF DEBUGF 52#else 53#define SDEBUGF(...) 54#endif 55#ifndef __PCTOOL__ 56#include "config.h" 57#include "system.h" 58#include <bmp.h> 59#include "resize.h" 60#else 61#undef DEBUGF 62#define DEBUGF(...) 63#endif 64#include <jpeg_load.h> 65 66#define MULUQ(a, b) ((a) * (b)) 67#define MULQ(a, b) ((a) * (b)) 68 69#ifdef HAVE_LCD_COLOR 70#define CHANNEL_BYTES (sizeof(struct uint32_argb)/sizeof(uint32_t)) 71#else 72#define CHANNEL_BYTES (sizeof(uint32_t)/sizeof(uint32_t)) /* packed */ 73#endif 74 75/* calculate the maximum dimensions which will preserve the aspect ration of 76 src while fitting in the constraints passed in dst, and store result in dst, 77 returning 0 if rounding and 1 if not rounding. 78*/ 79int recalc_dimension(struct dim *dst, struct dim *src) 80{ 81 /* This only looks backwards. The input image size is being pre-scaled by 82 * the inverse of the pixel aspect ratio, so that once the size it scaled 83 * to meet the output constraints, the scaled image will have appropriate 84 * proportions. 85 */ 86 int sw = src->width * LCD_PIXEL_ASPECT_HEIGHT; 87 int sh = src->height * LCD_PIXEL_ASPECT_WIDTH; 88 int tmp; 89 if (dst->width <= 0) 90 dst->width = LCD_WIDTH; 91 if (dst->height <= 0) 92 dst->height = LCD_HEIGHT; 93#ifndef HAVE_UPSCALER 94 if (dst->width > sw || dst->height > sh) 95 { 96 dst->width = sw; 97 dst->height = sh; 98 } 99 if (sw == dst->width && sh == dst->height) 100 return 1; 101#endif 102 tmp = (sw * dst->height + (sh >> 1)) / sh; 103 if (tmp > dst->width) 104 dst->height = (sh * dst->width + (sw >> 1)) / sw; 105 else 106 dst->width = tmp; 107 return src->width == dst->width && src->height == dst->height; 108} 109 110/* All of these scalers use variations of Bresenham's algorithm to convert from 111 their input to output coordinates. The error value is shifted from the 112 "classic" version such that it is a useful input to the scaling calculation. 113*/ 114 115#ifdef HAVE_LCD_COLOR 116/* dither + pack on channel of RGB565, R an B share a packing macro */ 117#define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8) 118#define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8) 119#endif 120 121/* read new img_part unconditionally, return false on failure */ 122#define FILL_BUF_INIT(img_part, store_part, args) { \ 123 img_part = store_part(args); \ 124 if (img_part == NULL) \ 125 return false; \ 126} 127 128/* read new img_part if current one is empty, return false on failure */ 129#define FILL_BUF(img_part, store_part, args) { \ 130 if (img_part->len == 0) \ 131 img_part = store_part(args); \ 132 if (img_part == NULL) \ 133 return false; \ 134} 135 136#if defined(CPU_COLDFIRE) 137#define MAC(op1, op2, num) \ 138 asm volatile( \ 139 "mac.l %0, %1, %%acc" #num \ 140 : \ 141 : "%d" (op1), "d" (op2)\ 142 ) 143#define MAC_OUT(dest, num) \ 144 asm volatile( \ 145 "movclr.l %%acc" #num ", %0" \ 146 : "=d" (dest) \ 147 ) 148#endif 149 150/* horizontal area average scaler */ 151static bool scale_h_area(void *out_line_ptr, 152 struct scaler_context *ctx, bool accum) 153{ 154 SDEBUGF("scale_h_area\n"); 155 unsigned int ix, ox, oxe, mul; 156 const uint32_t h_i_val = ctx->h_i_val, 157 h_o_val = ctx->h_o_val; 158#ifdef HAVE_LCD_COLOR 159 struct uint32_argb rgbvalacc = { 0, 0, 0, 0 }, 160 rgbvaltmp = { 0, 0, 0, 0 }, 161 *out_line = (struct uint32_argb *)out_line_ptr; 162#else 163 uint32_t acc = 0, tmp = 0, *out_line = (uint32_t*)out_line_ptr; 164#endif 165 struct img_part *part; 166 FILL_BUF_INIT(part,ctx->store_part,ctx->args); 167 ox = 0; 168 oxe = 0; 169 mul = 0; 170 /* give other tasks a chance to run */ 171 yield(); 172 for (ix = 0; ix < (unsigned int)ctx->src->width; ix++) 173 { 174 oxe += h_o_val; 175 /* end of current area has been reached */ 176 /* fill buffer if needed */ 177 FILL_BUF(part,ctx->store_part,ctx->args); 178#ifdef HAVE_LCD_COLOR 179 if (oxe >= h_i_val) 180 { 181 /* "reset" error, which now represents partial coverage of next 182 pixel by the next area 183 */ 184 oxe -= h_i_val; 185 186#if defined(CPU_COLDFIRE) 187/* Coldfire EMAC math */ 188 /* add saved partial pixel from start of area */ 189 MAC(rgbvalacc.r, h_o_val, 0); 190 MAC(rgbvalacc.g, h_o_val, 1); 191 MAC(rgbvalacc.b, h_o_val, 2); 192 MAC(rgbvalacc.a, h_o_val, 3); 193 MAC(rgbvaltmp.r, mul, 0); 194 MAC(rgbvaltmp.g, mul, 1); 195 MAC(rgbvaltmp.b, mul, 2); 196 MAC(rgbvaltmp.a, mul, 3); 197 /* get new pixel , then add its partial coverage to this area */ 198 mul = h_o_val - oxe; 199 rgbvaltmp.r = part->buf->red; 200 rgbvaltmp.g = part->buf->green; 201 rgbvaltmp.b = part->buf->blue; 202 rgbvaltmp.a = part->buf->alpha; 203 MAC(rgbvaltmp.r, mul, 0); 204 MAC(rgbvaltmp.g, mul, 1); 205 MAC(rgbvaltmp.b, mul, 2); 206 MAC(rgbvaltmp.a, mul, 3); 207 MAC_OUT(rgbvalacc.r, 0); 208 MAC_OUT(rgbvalacc.g, 1); 209 MAC_OUT(rgbvalacc.b, 2); 210 MAC_OUT(rgbvalacc.a, 3); 211#else 212/* generic C math */ 213 /* add saved partial pixel from start of area */ 214 rgbvalacc.r = rgbvalacc.r * h_o_val + rgbvaltmp.r * mul; 215 rgbvalacc.g = rgbvalacc.g * h_o_val + rgbvaltmp.g * mul; 216 rgbvalacc.b = rgbvalacc.b * h_o_val + rgbvaltmp.b * mul; 217 rgbvalacc.a = rgbvalacc.a * h_o_val + rgbvaltmp.a * mul; 218 219 /* get new pixel , then add its partial coverage to this area */ 220 rgbvaltmp.r = part->buf->red; 221 rgbvaltmp.g = part->buf->green; 222 rgbvaltmp.b = part->buf->blue; 223 rgbvaltmp.a = part->buf->alpha; 224 mul = h_o_val - oxe; 225 rgbvalacc.r += rgbvaltmp.r * mul; 226 rgbvalacc.g += rgbvaltmp.g * mul; 227 rgbvalacc.b += rgbvaltmp.b * mul; 228 rgbvalacc.a += rgbvaltmp.a * mul; 229#endif /* CPU */ 230 rgbvalacc.r = (rgbvalacc.r + (1 << 21)) >> 22; 231 rgbvalacc.g = (rgbvalacc.g + (1 << 21)) >> 22; 232 rgbvalacc.b = (rgbvalacc.b + (1 << 21)) >> 22; 233 rgbvalacc.a = (rgbvalacc.a + (1 << 21)) >> 22; 234 /* store or accumulate to output row */ 235 if (accum) 236 { 237 rgbvalacc.r += out_line[ox].r; 238 rgbvalacc.g += out_line[ox].g; 239 rgbvalacc.b += out_line[ox].b; 240 rgbvalacc.a += out_line[ox].a; 241 } 242 out_line[ox].r = rgbvalacc.r; 243 out_line[ox].g = rgbvalacc.g; 244 out_line[ox].b = rgbvalacc.b; 245 out_line[ox].a = rgbvalacc.a; 246 /* reset accumulator */ 247 rgbvalacc.r = 0; 248 rgbvalacc.g = 0; 249 rgbvalacc.b = 0; 250 rgbvalacc.a = 0; 251 mul = oxe; 252 ox += 1; 253 /* inside an area */ 254 } else { 255 /* add pixel value to accumulator */ 256 rgbvalacc.r += part->buf->red; 257 rgbvalacc.g += part->buf->green; 258 rgbvalacc.b += part->buf->blue; 259 rgbvalacc.a += part->buf->alpha; 260 } 261#else 262 if (oxe >= h_i_val) 263 { 264 /* "reset" error, which now represents partial coverage of next 265 pixel by the next area 266 */ 267 oxe -= h_i_val; 268#if defined(CPU_COLDFIRE) 269/* Coldfire EMAC math */ 270 /* add saved partial pixel from start of area */ 271 MAC(acc, h_o_val, 0); 272 MAC(tmp, mul, 0); 273 /* get new pixel , then add its partial coverage to this area */ 274 tmp = *(part->buf); 275 mul = h_o_val - oxe; 276 MAC(tmp, mul, 0); 277 MAC_OUT(acc, 0); 278#else 279/* generic C math */ 280 /* add saved partial pixel from start of area */ 281 acc = (acc * h_o_val) + (tmp * mul); 282 283 /* get new pixel , then add its partial coverage to this area */ 284 tmp = *(part->buf); 285 mul = h_o_val - oxe; 286 acc += tmp * mul; 287#endif /* CPU */ 288 /* round, divide, and either store or accumulate to output row */ 289 acc = (acc + (1 << 21)) >> 22; 290 if (accum) 291 { 292 acc += out_line[ox]; 293 } 294 out_line[ox] = acc; 295 /* reset accumulator */ 296 acc = 0; 297 mul = oxe; 298 ox += 1; 299 /* inside an area */ 300 } else { 301 /* add pixel value to accumulator */ 302 acc += *(part->buf); 303 } 304#endif 305 part->buf++; 306 part->len--; 307 } 308 return true; 309} 310 311/* vertical area average scaler */ 312static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx) 313{ 314 uint32_t mul, oy, iy, oye; 315 const uint32_t v_i_val = ctx->v_i_val, 316 v_o_val = ctx->v_o_val; 317 318 /* Set up rounding and scale factors */ 319 mul = 0; 320 oy = rset->rowstart; 321 oye = 0; 322 uint32_t *rowacc = (uint32_t *) ctx->buf, 323 *rowtmp = rowacc + ctx->bm->width * CHANNEL_BYTES, 324 *rowacc_px, *rowtmp_px; 325 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t)*CHANNEL_BYTES); 326 SDEBUGF("scale_v_area\n"); 327 /* zero the accumulator and temp rows */ 328 for (iy = 0; iy < (unsigned int)ctx->src->height; iy++) 329 { 330 oye += v_o_val; 331 /* end of current area has been reached */ 332 if (oye >= v_i_val) 333 { 334 /* "reset" error, which now represents partial coverage of the next 335 row by the next area 336 */ 337 oye -= v_i_val; 338 /* add stored partial row to accumulator */ 339 for(rowacc_px = rowacc, rowtmp_px = rowtmp; rowacc_px != rowtmp; 340 rowacc_px++, rowtmp_px++) 341 *rowacc_px = *rowacc_px * v_o_val + *rowtmp_px * mul; 342 /* store new scaled row in temp row */ 343 if(!ctx->h_scaler(rowtmp, ctx, false)) 344 return false; 345 /* add partial coverage by new row to this area, then round and 346 scale to final value 347 */ 348 mul = v_o_val - oye; 349 for(rowacc_px = rowacc, rowtmp_px = rowtmp; rowacc_px != rowtmp; 350 rowacc_px++, rowtmp_px++) 351 *rowacc_px += mul * *rowtmp_px; 352 ctx->output_row(oy, (void*)rowacc, ctx); 353 /* clear accumulator row, store partial coverage for next row */ 354 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * CHANNEL_BYTES); 355 mul = oye; 356 oy += rset->rowstep; 357 /* inside an area */ 358 } else { 359 /* accumulate new scaled row to rowacc */ 360 if (!ctx->h_scaler(rowacc, ctx, true)) 361 return false; 362 } 363 } 364 return true; 365} 366 367#ifdef HAVE_UPSCALER 368/* horizontal linear scaler */ 369static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx, 370 bool accum) 371{ 372 unsigned int ix, ox, ixe; 373 const uint32_t h_i_val = ctx->h_i_val, 374 h_o_val = ctx->h_o_val; 375 /* type x = x is an ugly hack for hiding an unitialized data warning. The 376 values are conditionally initialized before use, but other values are 377 set such that this will occur before these are used. 378 */ 379#ifdef HAVE_LCD_COLOR 380 struct uint32_argb rgbval=rgbval, rgbinc=rgbinc, 381 *out_line = (struct uint32_argb*)out_line_ptr; 382#else 383 uint32_t val=val, inc=inc, *out_line = (uint32_t*)out_line_ptr; 384#endif 385 struct img_part *part; 386 SDEBUGF("scale_h_linear\n"); 387 FILL_BUF_INIT(part,ctx->store_part,ctx->args); 388 ix = 0; 389 /* The error is set so that values are initialized on the first pass. */ 390 ixe = h_o_val; 391 /* give other tasks a chance to run */ 392 yield(); 393 for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++) 394 { 395#ifdef HAVE_LCD_COLOR 396 if (ixe >= h_o_val) 397 { 398 /* Store the new "current" pixel value in rgbval, and the color 399 step value in rgbinc. 400 */ 401 ixe -= h_o_val; 402 rgbinc.r = -(part->buf->red); 403 rgbinc.g = -(part->buf->green); 404 rgbinc.b = -(part->buf->blue); 405 rgbinc.a = -(part->buf->alpha); 406#if defined(CPU_COLDFIRE) 407/* Coldfire EMAC math */ 408 MAC(part->buf->red, h_o_val, 0); 409 MAC(part->buf->green, h_o_val, 1); 410 MAC(part->buf->blue, h_o_val, 2); 411 MAC(part->buf->alpha, h_o_val, 3); 412#else 413/* generic C math */ 414 rgbval.r = (part->buf->red) * h_o_val; 415 rgbval.g = (part->buf->green) * h_o_val; 416 rgbval.b = (part->buf->blue) * h_o_val; 417 rgbval.a = (part->buf->alpha) * h_o_val; 418#endif /* CPU */ 419 ix += 1; 420 /* If this wasn't the last pixel, add the next one to rgbinc. */ 421 if (LIKELY(ix < (uint32_t)ctx->src->width)) { 422 part->buf++; 423 part->len--; 424 /* Fetch new pixels if needed */ 425 FILL_BUF(part,ctx->store_part,ctx->args); 426 rgbinc.r += part->buf->red; 427 rgbinc.g += part->buf->green; 428 rgbinc.b += part->buf->blue; 429 rgbinc.a += part->buf->alpha; 430 /* Add a partial step to rgbval, in this pixel isn't precisely 431 aligned with the new source pixel 432 */ 433#if defined(CPU_COLDFIRE) 434/* Coldfire EMAC math */ 435 MAC(rgbinc.r, ixe, 0); 436 MAC(rgbinc.g, ixe, 1); 437 MAC(rgbinc.b, ixe, 2); 438 MAC(rgbinc.a, ixe, 3); 439#else 440/* generic C math */ 441 rgbval.r += rgbinc.r * ixe; 442 rgbval.g += rgbinc.g * ixe; 443 rgbval.b += rgbinc.b * ixe; 444 rgbval.a += rgbinc.a * ixe; 445#endif 446 } 447#if defined(CPU_COLDFIRE) 448/* get final EMAC result out of ACC registers */ 449 MAC_OUT(rgbval.r, 0); 450 MAC_OUT(rgbval.g, 1); 451 MAC_OUT(rgbval.b, 2); 452 MAC_OUT(rgbval.a, 3); 453#endif 454 /* Now multiply the color increment to its proper value */ 455 rgbinc.r *= h_i_val; 456 rgbinc.g *= h_i_val; 457 rgbinc.b *= h_i_val; 458 rgbinc.a *= h_i_val; 459 } else { 460 rgbval.r += rgbinc.r; 461 rgbval.g += rgbinc.g; 462 rgbval.b += rgbinc.b; 463 rgbval.a += rgbinc.a; 464 } 465 /* round and scale values, and accumulate or store to output */ 466 if (accum) 467 { 468 out_line[ox].r += (rgbval.r + (1 << 21)) >> 22; 469 out_line[ox].g += (rgbval.g + (1 << 21)) >> 22; 470 out_line[ox].b += (rgbval.b + (1 << 21)) >> 22; 471 out_line[ox].a += (rgbval.a + (1 << 21)) >> 22; 472 } else { 473 out_line[ox].r = (rgbval.r + (1 << 21)) >> 22; 474 out_line[ox].g = (rgbval.g + (1 << 21)) >> 22; 475 out_line[ox].b = (rgbval.b + (1 << 21)) >> 22; 476 out_line[ox].a = (rgbval.a + (1 << 21)) >> 22; 477 } 478#else 479 if (ixe >= h_o_val) 480 { 481 /* Store the new "current" pixel value in rgbval, and the color 482 step value in rgbinc. 483 */ 484 ixe -= h_o_val; 485 val = *(part->buf); 486 inc = -val; 487#if defined(CPU_COLDFIRE) 488/* Coldfire EMAC math */ 489 MAC(val, h_o_val, 0); 490#else 491/* generic C math */ 492 val = val * h_o_val; 493#endif 494 ix += 1; 495 /* If this wasn't the last pixel, add the next one to rgbinc. */ 496 if (LIKELY(ix < (uint32_t)ctx->src->width)) { 497 part->buf++; 498 part->len--; 499 /* Fetch new pixels if needed */ 500 FILL_BUF(part,ctx->store_part,ctx->args); 501 inc += *(part->buf); 502 /* Add a partial step to rgbval, in this pixel isn't precisely 503 aligned with the new source pixel 504 */ 505#if defined(CPU_COLDFIRE) 506/* Coldfire EMAC math */ 507 MAC(inc, ixe, 0); 508#else 509/* generic C math */ 510 val += inc * ixe; 511#endif 512 } 513#if defined(CPU_COLDFIRE) 514/* get final EMAC result out of ACC register */ 515 MAC_OUT(val, 0); 516#endif 517 /* Now multiply the color increment to its proper value */ 518/* generic C math */ 519 inc *= h_i_val; 520 } else 521 val += inc; 522 /* round and scale values, and accumulate or store to output */ 523 if (accum) 524 { 525 out_line[ox] += (val + (1 << 21)) >> 22; 526 } else { 527 out_line[ox] = (val + (1 << 21)) >> 22; 528 } 529#endif 530 ixe += h_i_val; 531 } 532 return true; 533} 534 535/* vertical linear scaler */ 536static inline bool scale_v_linear(struct rowset *rset, 537 struct scaler_context *ctx) 538{ 539 uint32_t iy, iye; 540 int32_t oy; 541 const uint32_t v_i_val = ctx->v_i_val, 542 v_o_val = ctx->v_o_val; 543 /* Set up our buffers, to store the increment and current value for each 544 column, and one temp buffer used to read in new rows. 545 */ 546 uint32_t *rowinc = (uint32_t *)(ctx->buf), 547 *rowval = rowinc + ctx->bm->width * CHANNEL_BYTES, 548 *rowtmp = rowval + ctx->bm->width * CHANNEL_BYTES, 549 *rowinc_px, *rowval_px, *rowtmp_px; 550 551 SDEBUGF("scale_v_linear\n"); 552 iy = 0; 553 iye = v_o_val; 554 /* get first scaled row in rowtmp */ 555 if(!ctx->h_scaler((void*)rowtmp, ctx, false)) 556 return false; 557 for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep) 558 { 559 if (iye >= v_o_val) 560 { 561 iye -= v_o_val; 562 iy += 1; 563 for(rowinc_px = rowinc, rowtmp_px = rowtmp, rowval_px = rowval; 564 rowinc_px < rowval; rowinc_px++, rowtmp_px++, rowval_px++) 565 { 566 *rowinc_px = -*rowtmp_px; 567 *rowval_px = *rowtmp_px * v_o_val; 568 } 569 if (iy < (uint32_t)ctx->src->height) 570 { 571 if (!ctx->h_scaler((void*)rowtmp, ctx, false)) 572 return false; 573 for(rowinc_px = rowinc, rowtmp_px = rowtmp, rowval_px = rowval; 574 rowinc_px < rowval; rowinc_px++, rowtmp_px++, rowval_px++) 575 { 576 *rowinc_px += *rowtmp_px; 577 *rowval_px += *rowinc_px * iye; 578 *rowinc_px *= v_i_val; 579 } 580 } 581 } else 582 for(rowinc_px = rowinc, rowval_px = rowval; rowinc_px < rowval; 583 rowinc_px++, rowval_px++) 584 *rowval_px += *rowinc_px; 585 ctx->output_row(oy, (void*)rowval, ctx); 586 iye += v_i_val; 587 } 588 return true; 589} 590#endif /* HAVE_UPSCALER */ 591 592#if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN)) 593static void output_row_32_native_fromyuv(uint32_t row, void * row_in, 594 struct scaler_context *ctx) 595{ 596#if LCD_STRIDEFORMAT == VERTICAL_STRIDE 597#define DEST_STEP (ctx->bm->height) 598#define Y_STEP (1) 599#else 600#define DEST_STEP (1) 601#define Y_STEP (BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0)) 602#endif 603 604 int col; 605 uint8_t dy = DITHERY(row); 606 struct uint32_argb *qp = (struct uint32_argb *)row_in; 607 SDEBUGF("output_row: y: %lu in: %p\n",row, row_in); 608 fb_data *dest = (fb_data *)ctx->bm->data + Y_STEP * row; 609 int delta = 127; 610 unsigned r, g, b, y, u, v; 611 612 for (col = 0; col < ctx->bm->width; col++) { 613 (void) delta; 614 if (ctx->dither) 615 delta = DITHERXDY(col,dy); 616 y = SC_OUT(qp->b, ctx); 617 u = SC_OUT(qp->g, ctx); 618 v = SC_OUT(qp->r, ctx); 619 qp++; 620 yuv_to_rgb(y, u, v, &r, &g, &b); 621#if LCD_DEPTH < 24 622 r = (31 * r + (r >> 3) + delta) >> 8; 623 g = (63 * g + (g >> 2) + delta) >> 8; 624 b = (31 * b + (b >> 3) + delta) >> 8; 625#endif 626 *dest = FB_RGBPACK_LCD(r, g, b); 627 dest += DEST_STEP; 628 } 629} 630#endif 631 632#if !defined(PLUGIN) || LCD_DEPTH > 1 633static void output_row_32_native(uint32_t row, void * row_in, 634 struct scaler_context *ctx) 635{ 636 int col; 637 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0); 638 uint8_t dy = DITHERY(row); 639#ifdef HAVE_LCD_COLOR 640 struct uint32_argb *qp = (struct uint32_argb*)row_in; 641#else 642 uint32_t *qp = (uint32_t*)row_in; 643#endif 644 SDEBUGF("output_row: y: %lu in: %p\n",row, row_in); 645#if LCD_DEPTH == 2 646#if LCD_PIXELFORMAT == HORIZONTAL_PACKING 647 /* greyscale iPods */ 648 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row; 649 int shift = 6; 650 int delta = 127; 651 unsigned bright; 652 unsigned data = 0; 653 654 for (col = 0; col < ctx->bm->width; col++) { 655 if (ctx->dither) 656 delta = DITHERXDY(col,dy); 657 bright = SC_OUT(*qp++, ctx); 658 bright = (3 * bright + (bright >> 6) + delta) >> 8; 659 data |= (~bright & 3) << shift; 660 shift -= 2; 661 if (shift < 0) { 662 *dest++ = data; 663 data = 0; 664 shift = 6; 665 } 666 } 667 if (shift < 6) 668 *dest++ = data; 669#elif LCD_PIXELFORMAT == VERTICAL_PACKING 670 /* iriver H1x0 */ 671 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * 672 (row >> 2); 673 int shift = 2 * (row & 3); 674 int delta = 127; 675 unsigned bright; 676 677 for (col = 0; col < ctx->bm->width; col++) { 678 if (ctx->dither) 679 delta = DITHERXDY(col,dy); 680 bright = SC_OUT(*qp++, ctx); 681 bright = (3 * bright + (bright >> 6) + delta) >> 8; 682 *dest++ |= (~bright & 3) << shift; 683 } 684#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED 685 /* iAudio M3 */ 686 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * 687 (row >> 3); 688 int shift = row & 7; 689 int delta = 127; 690 unsigned bright; 691 692 for (col = 0; col < ctx->bm->width; col++) { 693 if (ctx->dither) 694 delta = DITHERXDY(col,dy); 695 bright = SC_OUT(*qp++, ctx); 696 bright = (3 * bright + (bright >> 6) + delta) >> 8; 697 *dest++ |= vi_pattern[bright] << shift; 698 } 699#endif /* LCD_PIXELFORMAT */ 700#elif LCD_DEPTH >= 16 701 /* iriver h300, colour iPods, X5 */ 702 (void)fb_width; 703 fb_data *dest = STRIDE_MAIN((fb_data *)ctx->bm->data + fb_width * row, 704 (fb_data *)ctx->bm->data + row); 705 int delta = 127; 706 unsigned r, g, b; 707 struct uint32_argb q0; 708 /* setup alpha channel buffer */ 709 unsigned char *bm_alpha = NULL; 710 if (ctx->bm->alpha_offset > 0) 711 bm_alpha = ctx->bm->data + ctx->bm->alpha_offset; 712 if (bm_alpha) 713 bm_alpha += ALIGN_UP(ctx->bm->width, 2)*row/2; 714 715 for (col = 0; col < ctx->bm->width; col++) { 716 (void) delta; 717 if (ctx->dither) 718 delta = DITHERXDY(col,dy); 719 q0 = *qp++; 720 r = SC_OUT(q0.r, ctx); 721 g = SC_OUT(q0.g, ctx); 722 b = SC_OUT(q0.b, ctx); 723#if LCD_DEPTH < 24 724 r = (31 * r + (r >> 3) + delta) >> 8; 725 g = (63 * g + (g >> 2) + delta) >> 8; 726 b = (31 * b + (b >> 3) + delta) >> 8; 727#endif 728 *dest = FB_RGBPACK_LCD(r, g, b); 729 dest += STRIDE_MAIN(1, ctx->bm->height); 730 if (bm_alpha) { 731 /* pack alpha channel for 2 pixels into 1 byte */ 732 unsigned alpha = SC_OUT(q0.a, ctx); 733 if (col%2) 734 *bm_alpha++ |= alpha&0xf0; 735 else 736 *bm_alpha = alpha>>4; 737 } 738 } 739#endif /* LCD_DEPTH */ 740} 741#endif 742 743#if defined(PLUGIN) && LCD_DEPTH > 1 744unsigned int get_size_native(struct bitmap *bm) 745{ 746 return BM_SIZE(bm->width,bm->height,FORMAT_NATIVE,0); 747} 748 749const struct custom_format format_native = { 750 .output_row_8 = output_row_8_native, 751#if defined(HAVE_LCD_COLOR) && (defined(HAVE_JPEG) || defined(PLUGIN)) 752 .output_row_32 = { 753 output_row_32_native, 754 output_row_32_native_fromyuv 755 }, 756#else 757 .output_row_32 = output_row_32_native, 758#endif 759 .get_size = get_size_native 760}; 761#endif 762 763int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, 764 struct rowset *rset, unsigned char *buf, unsigned int len, 765 const struct custom_format *format, 766 IF_PIX_FMT(int format_index,) 767 struct img_part* (*store_part)(void *args), 768 void *args) 769{ 770 const int sw = src->width; 771 const int sh = src->height; 772 const int dw = bm->width; 773 const int dh = bm->height; 774 int ret; 775 /* buffer for 1 line + 2 spare lines */ 776#ifdef HAVE_LCD_COLOR 777 unsigned int needed = sizeof(struct uint32_argb) * 3 * bm->width; 778#else 779 unsigned int needed = sizeof(uint32_t) * 3 * bm->width; 780#endif 781#if MAX_SC_STACK_ALLOC 782 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? 783 0 : needed]; 784#endif 785 ALIGN_BUFFER(buf, len, sizeof(uint32_t)); 786 if (needed > len) 787 { 788#if MAX_SC_STACK_ALLOC 789 if (needed > MAX_SC_STACK_ALLOC) 790 { 791 DEBUGF("unable to allocate required buffer: %d needed, " 792 "%d available, %d permitted from stack\n", 793 needed, len, MAX_SC_STACK_ALLOC); 794 return 0; 795 } 796 if (sizeof(sc_buf) < needed) 797 { 798 DEBUGF("failed to allocate large enough buffer on stack: " 799 "%d needed, only got %d", 800 needed, MAX_SC_STACK_ALLOC); 801 return 0; 802 } 803#else 804 DEBUGF("unable to allocate required buffer: %d needed, " 805 "%d available\n", needed, len); 806 return 0; 807#endif 808 } 809 810 struct scaler_context ctx; 811#ifdef HAVE_ADJUSTABLE_CPU_FREQ 812 cpu_boost(true); 813#endif 814 ctx.store_part = store_part; 815 ctx.args = args; 816#if MAX_SC_STACK_ALLOC 817 ctx.buf = needed > len ? sc_buf : buf; 818#else 819 ctx.buf = buf; 820#endif 821 ctx.len = len; 822 ctx.bm = bm; 823 ctx.src = src; 824 ctx.dither = dither; 825#if !defined(PLUGIN) 826#if defined(HAVE_LCD_COLOR) && defined(HAVE_JPEG) 827 ctx.output_row = format_index ? output_row_32_native_fromyuv 828 : output_row_32_native; 829#else 830 ctx.output_row = output_row_32_native; 831#endif 832 if (format) 833#endif 834#ifdef HAVE_LCD_COLOR 835 ctx.output_row = format->output_row_32[format_index]; 836#else 837 ctx.output_row = format->output_row_32; 838#endif 839#ifdef HAVE_UPSCALER 840 if (sw > dw) 841 { 842#endif 843 ctx.h_scaler = scale_h_area; 844 uint32_t h_div = (1U << 24) / sw; 845 ctx.h_i_val = sw * h_div; 846 ctx.h_o_val = dw * h_div; 847#ifdef HAVE_UPSCALER 848 } else { 849 ctx.h_scaler = scale_h_linear; 850 uint32_t h_div = (1U << 24) / (dw - 1); 851 ctx.h_i_val = (sw - 1) * h_div; 852 ctx.h_o_val = (dw - 1) * h_div; 853 } 854#endif 855#ifdef CPU_COLDFIRE 856 unsigned old_macsr = coldfire_get_macsr(); 857 coldfire_set_macsr(EMAC_UNSIGNED); 858#endif 859#ifdef HAVE_UPSCALER 860 if (sh > dh) 861#endif 862 { 863 uint32_t v_div = (1U << 22) / sh; 864 ctx.v_i_val = sh * v_div; 865 ctx.v_o_val = dh * v_div; 866 ret = scale_v_area(rset, &ctx); 867 } 868#ifdef HAVE_UPSCALER 869 else 870 { 871 uint32_t v_div = (1U << 22) / dh; 872 ctx.v_i_val = (sh - 1) * v_div; 873 ctx.v_o_val = (dh - 1) * v_div; 874 ret = scale_v_linear(rset, &ctx); 875 } 876#endif 877#ifdef CPU_COLDFIRE 878 /* Restore emac status; other modules like tone control filter 879 * calculation may rely on it. */ 880 coldfire_set_macsr(old_macsr); 881#endif 882#ifdef HAVE_ADJUSTABLE_CPU_FREQ 883 cpu_boost(false); 884#endif 885 if (!ret) 886 return 0; 887 return 1; 888}