1/* 2 * Copyright (C) 2010-2011 Julien BLACHE <jb@jblache.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <stdio.h> 24#include <stdlib.h> 25#include <unistd.h> 26#include <string.h> 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <fcntl.h> 30#include <limits.h> 31 32#include <libavcodec/avcodec.h> 33#include <libavformat/avformat.h> 34#include <libswscale/swscale.h> 35 36#include "event.h" 37#include "db.h" 38#include "logger.h" 39#if LIBAVFORMAT_VERSION_MAJOR >= 53 40# include "avio_evbuffer.h" 41#endif 42#include "artwork.h" 43 44 45static const char *cover_basename[] = 46 { 47 "artwork", "cover", 48 }; 49 50static const char *cover_extension[] = 51 { 52 "png", "jpg", 53 }; 54 55 56static int 57artwork_read(char *filename, struct evbuffer *evbuf) 58{ 59 uint8_t buf[4096]; 60 struct stat sb; 61 int fd; 62 int ret; 63 64 fd = open(filename, O_RDONLY); 65 if (fd < 0) 66 { 67 DPRINTF(E_WARN, L_ART, "Could not open artwork file '%s': %s\n", filename, strerror(errno)); 68 69 return -1; 70 } 71 72 ret = fstat(fd, &sb); 73 if (ret < 0) 74 { 75 DPRINTF(E_WARN, L_ART, "Could not stat() artwork file '%s': %s\n", filename, strerror(errno)); 76 77 goto out_fail; 78 } 79 80 ret = evbuffer_expand(evbuf, sb.st_size); 81 if (ret < 0) 82 { 83 DPRINTF(E_LOG, L_ART, "Out of memory for artwork\n"); 84 85 goto out_fail; 86 } 87 88 while ((ret = read(fd, buf, sizeof(buf))) > 0) 89 evbuffer_add(evbuf, buf, ret); 90 91 close(fd); 92 93 return 0; 94 95 out_fail: 96 close(fd); 97 return -1; 98} 99 100static int 101artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int format, struct evbuffer *evbuf) 102{ 103 uint8_t *buf; 104 uint8_t *outbuf; 105 106 AVCodecContext *src; 107 108 AVFormatContext *dst_ctx; 109 AVCodecContext *dst; 110 AVOutputFormat *dst_fmt; 111 AVStream *dst_st; 112 113 AVCodec *img_decoder; 114 AVCodec *img_encoder; 115 116 int64_t pix_fmt_mask; 117 const enum PixelFormat *pix_fmts; 118 119 AVFrame *i_frame; 120 AVFrame *o_frame; 121 122 struct SwsContext *swsctx; 123 124 AVPacket pkt; 125 int have_frame; 126 127 int outbuf_len; 128 129 int ret; 130 131 src = src_ctx->streams[s]->codec; 132 133 img_decoder = avcodec_find_decoder(src->codec_id); 134 if (!img_decoder) 135 { 136 DPRINTF(E_LOG, L_ART, "No suitable decoder found for artwork %s\n", src_ctx->filename); 137 138 return -1; 139 } 140 141 ret = avcodec_open2(src, img_decoder,NULL); 142 if (ret < 0) 143 { 144 DPRINTF(E_LOG, L_ART, "Could not open codec for decoding: %s\n", strerror(AVUNERROR(ret))); 145 146 return -1; 147 } 148 149 /* Set up output */ 150#if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 52 && LIBAVFORMAT_VERSION_MINOR >= 45) 151 /* FFmpeg 0.6 */ 152 dst_fmt = av_guess_format("image2", NULL, NULL); 153#else 154 dst_fmt = guess_format("image2", NULL, NULL); 155#endif 156 if (!dst_fmt) 157 { 158 DPRINTF(E_LOG, L_ART, "ffmpeg image2 muxer not available\n"); 159 160 ret = -1; 161 goto out_close_src; 162 } 163 164 dst_fmt->video_codec = CODEC_ID_NONE; 165 166 /* Try to keep same codec if possible */ 167 if ((src->codec_id == CODEC_ID_PNG) && (format & ART_CAN_PNG)) 168 dst_fmt->video_codec = CODEC_ID_PNG; 169 else if ((src->codec_id == CODEC_ID_MJPEG) && (format & ART_CAN_JPEG)) 170 dst_fmt->video_codec = CODEC_ID_MJPEG; 171 172 /* If not possible, select new codec */ 173 if (dst_fmt->video_codec == CODEC_ID_NONE) 174 { 175 if (format & ART_CAN_PNG) 176 dst_fmt->video_codec = CODEC_ID_PNG; 177 else if (format & ART_CAN_JPEG) 178 dst_fmt->video_codec = CODEC_ID_MJPEG; 179 } 180 181 img_encoder = avcodec_find_encoder(dst_fmt->video_codec); 182 if (!img_encoder) 183 { 184 DPRINTF(E_LOG, L_ART, "No suitable encoder found for codec ID %d\n", dst_fmt->video_codec); 185 186 ret = -1; 187 goto out_close_src; 188 } 189 190 dst_ctx = avformat_alloc_context(); 191 if (!dst_ctx) 192 { 193 DPRINTF(E_LOG, L_ART, "Out of memory for format context\n"); 194 195 ret = -1; 196 goto out_close_src; 197 } 198 199 dst_ctx->oformat = dst_fmt; 200 201#if LIBAVFORMAT_VERSION_MAJOR >= 53 202 dst_fmt->flags &= ~AVFMT_NOFILE; 203#else 204 ret = snprintf(dst_ctx->filename, sizeof(dst_ctx->filename), "evbuffer:%p", evbuf); 205 if ((ret < 0) || (ret >= sizeof(dst_ctx->filename))) 206 { 207 DPRINTF(E_LOG, L_ART, "Output artwork URL too long\n"); 208 209 ret = -1; 210 goto out_free_dst_ctx; 211 } 212#endif 213 214 dst_st = avformat_new_stream(dst_ctx,NULL); 215 if (!dst_st) 216 { 217 DPRINTF(E_LOG, L_ART, "Out of memory for new output stream\n"); 218 219 ret = -1; 220 goto out_free_dst_ctx; 221 } 222 223 dst = dst_st->codec; 224 225#if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64) 226 avcodec_get_context_defaults3(dst, NULL); 227#else 228 avcodec_get_context_defaults3(dst, NULL); 229#endif 230 231 if (dst_fmt->flags & AVFMT_GLOBALHEADER) 232 dst->flags |= CODEC_FLAG_GLOBAL_HEADER; 233 234 dst->codec_id = dst_fmt->video_codec; 235#if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64) 236 dst->codec_type = AVMEDIA_TYPE_VIDEO; 237#else 238 dst->codec_type = CODEC_TYPE_VIDEO; 239#endif 240 241 pix_fmt_mask = 0; 242 pix_fmts = img_encoder->pix_fmts; 243 while (pix_fmts && (*pix_fmts != -1)) 244 { 245 pix_fmt_mask |= (1 << *pix_fmts); 246 pix_fmts++; 247 } 248 249 dst->pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src->pix_fmt, 1, NULL); 250 251 if (dst->pix_fmt < 0) 252 { 253 DPRINTF(E_LOG, L_ART, "Could not determine best pixel format\n"); 254 255 ret = -1; 256 goto out_free_dst; 257 } 258 259 DPRINTF(E_DBG, L_ART, "Selected pixel format: %d\n", dst->pix_fmt); 260 261 dst->time_base.num = 1; 262 dst->time_base.den = 25; 263 264 dst->width = out_w; 265 dst->height = out_h; 266 267#if LIBAVFORMAT_VERSION_MAJOR <= 52 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR <= 1) 268 ret = av_set_parameters(dst_ctx, NULL); 269 if (ret < 0) 270 { 271 DPRINTF(E_LOG, L_ART, "Invalid parameters for artwork output: %s\n", strerror(AVUNERROR(ret))); 272 273 ret = -1; 274 goto out_free_dst; 275 } 276#endif 277 278 /* Open encoder */ 279 ret = avcodec_open2(dst, img_encoder,NULL); 280 if (ret < 0) 281 { 282 DPRINTF(E_LOG, L_ART, "Could not open codec for encoding: %s\n", strerror(AVUNERROR(ret))); 283 284 ret = -1; 285 goto out_free_dst; 286 } 287 288 i_frame = avcodec_alloc_frame(); 289 o_frame = avcodec_alloc_frame(); 290 291 if (!i_frame || !o_frame) 292 { 293 DPRINTF(E_LOG, L_ART, "Could not allocate input/output frame\n"); 294 295 ret = -1; 296 goto out_free_frames; 297 } 298 299 ret = avpicture_get_size(dst->pix_fmt, src->width, src->height); 300 301 DPRINTF(E_DBG, L_ART, "Artwork buffer size: %d\n", ret); 302 303 buf = (uint8_t *)av_malloc(ret); 304 if (!buf) 305 { 306 DPRINTF(E_LOG, L_ART, "Out of memory for artwork buffer\n"); 307 308 ret = -1; 309 goto out_free_frames; 310 } 311 312 avpicture_fill((AVPicture *)o_frame, buf, dst->pix_fmt, src->width, src->height); 313 314 swsctx = sws_getContext(src->width, src->height, src->pix_fmt, 315 dst->width, dst->height, dst->pix_fmt, 316 SWS_BICUBIC, NULL, NULL, NULL); 317 if (!swsctx) 318 { 319 DPRINTF(E_LOG, L_ART, "Could not get SWS context\n"); 320 321 ret = -1; 322 goto out_free_buf; 323 } 324 325 /* Get frame */ 326 have_frame = 0; 327 while (av_read_frame(src_ctx, &pkt) == 0) 328 { 329 if (pkt.stream_index != s) 330 { 331 av_free_packet(&pkt); 332 continue; 333 } 334 335#if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 32) 336 /* FFmpeg 0.6 */ 337 avcodec_decode_video2(src, i_frame, &have_frame, &pkt); 338#else 339 avcodec_decode_video(src, i_frame, &have_frame, pkt.data, pkt.size); 340#endif 341 342 break; 343 } 344 345 if (!have_frame) 346 { 347 DPRINTF(E_LOG, L_ART, "Could not decode artwork\n"); 348 349 av_free_packet(&pkt); 350 sws_freeContext(swsctx); 351 352 ret = -1; 353 goto out_free_buf; 354 } 355 356 /* Scale */ 357#if LIBSWSCALE_VERSION_MAJOR >= 1 || (LIBSWSCALE_VERSION_MAJOR == 0 && LIBSWSCALE_VERSION_MINOR >= 9) 358 /* FFmpeg 0.6, libav 0.6+ */ 359 sws_scale(swsctx, (const uint8_t * const *)i_frame->data, i_frame->linesize, 0, src->height, o_frame->data, o_frame->linesize); 360#else 361 sws_scale(swsctx, i_frame->data, i_frame->linesize, 0, src->height, o_frame->data, o_frame->linesize); 362#endif 363 364 sws_freeContext(swsctx); 365 av_free_packet(&pkt); 366 367 /* Open output file */ 368#if LIBAVFORMAT_VERSION_MAJOR >= 53 369 dst_ctx->pb = avio_evbuffer_open(evbuf); 370#else 371 ret = url_fopen(&dst_ctx->pb, dst_ctx->filename, URL_WRONLY); 372#endif 373 if (ret < 0) 374 { 375 DPRINTF(E_LOG, L_ART, "Could not open artwork destination buffer\n"); 376 377 ret = -1; 378 goto out_free_buf; 379 } 380 381 /* Encode frame */ 382 outbuf_len = dst->width * dst->height * 3; 383 if (outbuf_len < FF_MIN_BUFFER_SIZE) 384 outbuf_len = FF_MIN_BUFFER_SIZE; 385 386 outbuf = (uint8_t *)av_malloc(outbuf_len); 387 if (!outbuf) 388 { 389 DPRINTF(E_LOG, L_ART, "Out of memory for encoded artwork buffer\n"); 390 391#if LIBAVFORMAT_VERSION_MAJOR >= 53 392 avio_evbuffer_close(dst_ctx->pb); 393#else 394 url_fclose(dst_ctx->pb); 395#endif 396 397 ret = -1; 398 goto out_free_buf; 399 } 400 401 ret = avcodec_encode_video(dst, outbuf, outbuf_len, o_frame); 402 if (ret <= 0) 403 { 404 DPRINTF(E_LOG, L_ART, "Could not encode artwork\n"); 405 406 ret = -1; 407 goto out_fclose_dst; 408 } 409 410 av_init_packet(&pkt); 411 pkt.stream_index = 0; 412 pkt.data = outbuf; 413 pkt.size = ret; 414 415#if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 3) 416 ret = avformat_write_header(dst_ctx, NULL); 417#else 418 ret = av_write_header(dst_ctx); 419#endif 420 if (ret != 0) 421 { 422 DPRINTF(E_LOG, L_ART, "Could not write artwork header: %s\n", strerror(AVUNERROR(ret))); 423 424 ret = -1; 425 goto out_fclose_dst; 426 } 427 428 ret = av_interleaved_write_frame(dst_ctx, &pkt); 429 430 if (ret != 0) 431 { 432 DPRINTF(E_LOG, L_ART, "Error writing artwork\n"); 433 434 ret = -1; 435 goto out_fclose_dst; 436 } 437 438 ret = av_write_trailer(dst_ctx); 439 if (ret != 0) 440 { 441 DPRINTF(E_LOG, L_ART, "Could not write artwork trailer: %s\n", strerror(AVUNERROR(ret))); 442 443 ret = -1; 444 goto out_fclose_dst; 445 } 446 447 switch (dst_fmt->video_codec) 448 { 449 case CODEC_ID_PNG: 450 ret = ART_FMT_PNG; 451 break; 452 453 case CODEC_ID_MJPEG: 454 ret = ART_FMT_JPEG; 455 break; 456 457 default: 458 DPRINTF(E_LOG, L_ART, "Unhandled rescale output format\n"); 459 ret = -1; 460 break; 461 } 462 463 out_fclose_dst: 464#if LIBAVFORMAT_VERSION_MAJOR >= 53 465 avio_evbuffer_close(dst_ctx->pb); 466#else 467 url_fclose(dst_ctx->pb); 468#endif 469 av_free(outbuf); 470 471 out_free_buf: 472 av_free(buf); 473 474 out_free_frames: 475 if (i_frame) 476 av_free(i_frame); 477 if (o_frame) 478 av_free(o_frame); 479 avcodec_close(dst); 480 481 out_free_dst: 482 av_free(dst_st); 483 av_free(dst); 484 485 out_free_dst_ctx: 486 av_free(dst_ctx); 487 488 out_close_src: 489 avcodec_close(src); 490 491 return ret; 492} 493 494static int 495artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *evbuf) 496{ 497 AVFormatContext *src_ctx; 498 AVCodecContext *src; 499 int s; 500 int target_w; 501 int target_h; 502 int need_rescale; 503 int format_ok; 504 int ret; 505 506 DPRINTF(E_DBG, L_ART, "Artwork request parameters: max w = %d, max h = %d\n", max_w, max_h); 507 508 src_ctx = NULL; 509 510#if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 3) 511 ret = avformat_open_input(&src_ctx, filename, NULL, NULL); 512#else 513 ret = av_open_input_file(&src_ctx, filename, NULL, 0, NULL); 514#endif 515 if (ret < 0) 516 { 517 DPRINTF(E_WARN, L_ART, "Cannot open artwork file '%s': %s\n", filename, strerror(AVUNERROR(ret))); 518 519 return -1; 520 } 521 522 ret = avformat_find_stream_info(src_ctx,NULL); 523 if (ret < 0) 524 { 525 DPRINTF(E_WARN, L_ART, "Cannot get stream info: %s\n", strerror(AVUNERROR(ret))); 526 527 av_close_input_file(src_ctx); 528 return -1; 529 } 530 531 format_ok = 0; 532 for (s = 0; s < src_ctx->nb_streams; s++) 533 { 534 if (src_ctx->streams[s]->codec->codec_id == CODEC_ID_PNG) 535 { 536 format_ok = (format & ART_CAN_PNG) ? ART_FMT_PNG : 0; 537 break; 538 } 539 else if (src_ctx->streams[s]->codec->codec_id == CODEC_ID_MJPEG) 540 { 541 format_ok = (format & ART_CAN_JPEG) ? ART_FMT_JPEG : 0; 542 break; 543 } 544 } 545 546 if (s == src_ctx->nb_streams) 547 { 548 DPRINTF(E_LOG, L_ART, "Artwork file '%s' not a PNG or JPEG file\n", filename); 549 550 av_close_input_file(src_ctx); 551 return -1; 552 } 553 554 src = src_ctx->streams[s]->codec; 555 556 DPRINTF(E_DBG, L_ART, "Original image '%s': w %d h %d\n", filename, src->width, src->height); 557 558 need_rescale = 1; 559 560 /* Determine width/height -- assuming max_w == max_h */ 561 if ((src->width <= max_w) && (src->height <= max_h)) 562 { 563 need_rescale = 0; 564 565 target_w = src->width; 566 target_h = src->height; 567 } 568 else if (src->width > src->height) 569 { 570 target_w = max_w; 571 target_h = (double)max_h * ((double)src->height / (double)src->width); 572 } 573 else if (src->height > src->width) 574 { 575 target_h = max_h; 576 target_w = (double)max_w * ((double)src->width / (double)src->height); 577 } 578 else 579 { 580 target_w = max_w; 581 target_h = max_h; 582 } 583 584 DPRINTF(E_DBG, L_ART, "Raw destination width %d height %d\n", target_w, target_h); 585 586 if (target_h > max_h) 587 target_h = max_h; 588 589 /* PNG prefers even row count */ 590 target_w += target_w % 2; 591 592 if (target_w > max_w) 593 target_w = max_w - (max_w % 2); 594 595 DPRINTF(E_DBG, L_ART, "Destination width %d height %d\n", target_w, target_h); 596 597 /* Fastpath */ 598 if (!need_rescale && format_ok) 599 { 600 ret = artwork_read(filename, evbuf); 601 if (ret == 0) 602 ret = format_ok; 603 } 604 else 605 ret = artwork_rescale(src_ctx, s, target_w, target_h, format, evbuf); 606 607 av_close_input_file(src_ctx); 608 609 if (ret < 0) 610 { 611 if (EVBUFFER_LENGTH(evbuf) > 0) 612 evbuffer_drain(evbuf, EVBUFFER_LENGTH(evbuf)); 613 } 614 615 return ret; 616} 617 618 619static int 620artwork_get_own_image(char *path, int max_w, int max_h, int format, struct evbuffer *evbuf) 621{ 622 char artwork[PATH_MAX]; 623 char *ptr; 624 int len; 625 int i; 626 int ret; 627 628 ret = snprintf(artwork, sizeof(artwork), "%s", path); 629 if ((ret < 0) || (ret >= sizeof(artwork))) 630 { 631 DPRINTF(E_INFO, L_ART, "Artwork path exceeds PATH_MAX\n"); 632 633 return -1; 634 } 635 636 ptr = strrchr(artwork, '.'); 637 if (ptr) 638 *ptr = '\0'; 639 640 len = strlen(artwork); 641 642 for (i = 0; i < (sizeof(cover_extension) / sizeof(cover_extension[0])); i++) 643 { 644 ret = snprintf(artwork + len, sizeof(artwork) - len, ".%s", cover_extension[i]); 645 if ((ret < 0) || (ret >= sizeof(artwork) - len)) 646 { 647 DPRINTF(E_INFO, L_ART, "Artwork path exceeds PATH_MAX (ext %s)\n", cover_extension[i]); 648 649 continue; 650 } 651 652 DPRINTF(E_DBG, L_ART, "Trying own artwork file %s\n", artwork); 653 654 ret = access(artwork, F_OK); 655 if (ret < 0) 656 continue; 657 658 break; 659 } 660 661 if (i == (sizeof(cover_extension) / sizeof(cover_extension[0]))) 662 return -1; 663 664 return artwork_get(artwork, max_w, max_h, format, evbuf); 665} 666 667static int 668artwork_get_dir_image(char *path, int isdir, int max_w, int max_h, int format, struct evbuffer *evbuf) 669{ 670 char artwork[PATH_MAX]; 671 char *ptr; 672 int i; 673 int j; 674 int len; 675 int ret; 676 677 ret = snprintf(artwork, sizeof(artwork), "%s", path); 678 if ((ret < 0) || (ret >= sizeof(artwork))) 679 { 680 DPRINTF(E_INFO, L_ART, "Artwork path exceeds PATH_MAX\n"); 681 682 return -1; 683 } 684 685 if (!isdir) 686 { 687 ptr = strrchr(artwork, '/'); 688 if (ptr) 689 *ptr = '\0'; 690 } 691 692 len = strlen(artwork); 693 694 for (i = 0; i < (sizeof(cover_basename) / sizeof(cover_basename[0])); i++) 695 { 696 for (j = 0; j < (sizeof(cover_extension) / sizeof(cover_extension[0])); j++) 697 { 698 ret = snprintf(artwork + len, sizeof(artwork) - len, "/%s.%s", cover_basename[i], cover_extension[j]); 699 if ((ret < 0) || (ret >= sizeof(artwork) - len)) 700 { 701 DPRINTF(E_INFO, L_ART, "Artwork path exceeds PATH_MAX (%s.%s)\n", cover_basename[i], cover_extension[j]); 702 703 continue; 704 } 705 706 DPRINTF(E_DBG, L_ART, "Trying directory artwork file %s\n", artwork); 707 708 ret = access(artwork, F_OK); 709 if (ret < 0) 710 continue; 711 712 break; 713 } 714 715 if (j < (sizeof(cover_extension) / sizeof(cover_extension[0]))) 716 break; 717 } 718 719 if (i == (sizeof(cover_basename) / sizeof(cover_basename[0]))) 720 return -1; 721 722 return artwork_get(artwork, max_w, max_h, format, evbuf); 723} 724 725 726int 727artwork_get_item_filename(char *filename, int max_w, int max_h, int format, struct evbuffer *evbuf) 728{ 729 int ret; 730 731 /* FUTURE: look at embedded artwork */ 732 733 /* Look for basename(filename).{png,jpg} */ 734 ret = artwork_get_own_image(filename, max_w, max_h, format, evbuf); 735 if (ret > 0) 736 return ret; 737 738 /* Look for basedir(filename)/{artwork,cover}.{png,jpg} */ 739 ret = artwork_get_dir_image(filename, 0, max_w, max_h, format, evbuf); 740 if (ret > 0) 741 return ret; 742 743 return -1; 744} 745 746int 747artwork_get_item(int id, int max_w, int max_h, int format, struct evbuffer *evbuf) 748{ 749 char *filename; 750 int ret; 751 752 DPRINTF(E_DBG, L_ART, "Artwork request for item %d\n", id); 753 754 filename = db_file_path_byid(id); 755 if (!filename) 756 return -1; 757 758 ret = artwork_get_item_filename(filename, max_w, max_h, format, evbuf); 759 if (ret < 0) 760 DPRINTF(E_DBG, L_ART, "No artwork found for item id %d\n", id); 761 762 free(filename); 763 764 return ret; 765} 766 767int 768artwork_get_group(int id, int max_w, int max_h, int format, struct evbuffer *evbuf) 769{ 770 struct query_params qp; 771 struct db_media_file_info dbmfi; 772 char *dir; 773 int got_art; 774 int ret; 775 776 DPRINTF(E_DBG, L_ART, "Artwork request for group %d\n", id); 777 778 /* Try directory artwork first */ 779 memset(&qp, 0, sizeof(struct query_params)); 780 781 qp.type = Q_GROUP_DIRS; 782 qp.id = id; 783 784 ret = db_query_start(&qp); 785 if (ret < 0) 786 { 787 DPRINTF(E_LOG, L_ART, "Could not start Q_GROUP_DIRS query\n"); 788 789 /* Skip to invidual files artwork */ 790 goto files_art; 791 } 792 793 got_art = -1; 794 while ((got_art < 0) && ((ret = db_query_fetch_string(&qp, &dir)) == 0) && (dir)) 795 { 796 got_art = artwork_get_dir_image(dir, 1, max_w, max_h, format, evbuf); 797 } 798 799 db_query_end(&qp); 800 801 if (ret < 0) 802 DPRINTF(E_LOG, L_ART, "Error fetching Q_GROUP_DIRS results\n"); 803 else if (got_art > 0) 804 return got_art; 805 806 807 /* Then try individual files */ 808 files_art: 809 memset(&qp, 0, sizeof(struct query_params)); 810 811 qp.type = Q_GROUP_ITEMS; 812 qp.id = id; 813 814 ret = db_query_start(&qp); 815 if (ret < 0) 816 { 817 DPRINTF(E_LOG, L_ART, "Could not start Q_GROUPITEMS query\n"); 818 819 return -1; 820 } 821 822 got_art = -1; 823 while ((got_art < 0) && ((ret = db_query_fetch_file(&qp, &dbmfi)) == 0) && (dbmfi.id)) 824 { 825 got_art = artwork_get_own_image(dbmfi.path, max_w, max_h, format, evbuf); 826 } 827 828 db_query_end(&qp); 829 830 if (ret < 0) 831 DPRINTF(E_LOG, L_ART, "Error fetching Q_GROUPITEMS results\n"); 832 else if (got_art > 0) 833 return got_art; 834 835 return -1; 836} 837