mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-15 08:45:02 -05:00
Use own libevent http client for downloading artwork, ffmpeg seems a
bit too slow
This commit is contained in:
parent
f947948a29
commit
96200eb808
121
src/artwork.c
121
src/artwork.c
@ -39,6 +39,7 @@
|
|||||||
#include "conffile.h"
|
#include "conffile.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
#include "http.h"
|
||||||
|
|
||||||
#if LIBAVFORMAT_VERSION_MAJOR >= 53
|
#if LIBAVFORMAT_VERSION_MAJOR >= 53
|
||||||
# include "avio_evbuffer.h"
|
# include "avio_evbuffer.h"
|
||||||
@ -697,14 +698,11 @@ artwork_get(char *path, int max_w, int max_h, struct evbuffer *evbuf)
|
|||||||
static int
|
static int
|
||||||
artwork_get_player_image(char *path, int max_w, int max_h, struct evbuffer *evbuf)
|
artwork_get_player_image(char *path, int max_w, int max_h, struct evbuffer *evbuf)
|
||||||
{
|
{
|
||||||
AVFormatContext *src_ctx;
|
struct http_client_ctx ctx;
|
||||||
AVPacket pkt;
|
struct keyval *kv;
|
||||||
|
const char *content_type;
|
||||||
char *url;
|
char *url;
|
||||||
int len;
|
int len;
|
||||||
int s;
|
|
||||||
int target_w;
|
|
||||||
int target_h;
|
|
||||||
int format_ok;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_ART, "Trying internet stream artwork in %s\n", path);
|
DPRINTF(E_DBG, L_ART, "Trying internet stream artwork in %s\n", path);
|
||||||
@ -717,100 +715,33 @@ artwork_get_player_image(char *path, int max_w, int max_h, struct evbuffer *evbu
|
|||||||
if ((len < 14) || (len > PATH_MAX)) // Can't be shorter than http://a/1.jpg
|
if ((len < 14) || (len > PATH_MAX)) // Can't be shorter than http://a/1.jpg
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
src_ctx = NULL;
|
kv = keyval_alloc();
|
||||||
ret = avformat_open_input(&src_ctx, url, NULL, NULL);
|
if (!kv)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
|
ctx.url = url;
|
||||||
|
ctx.async = 0;
|
||||||
|
ctx.headers = kv;
|
||||||
|
ctx.body = evbuf;
|
||||||
|
|
||||||
|
ret = http_client_request(&ctx);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
return 0;
|
||||||
DPRINTF(E_WARN, L_ART, "Cannot open artwork file '%s': %s\n", url, strerror(AVUNERROR(ret)));
|
|
||||||
|
|
||||||
return 0;
|
content_type = keyval_get(kv, "Content-Type");
|
||||||
}
|
if (strcmp(content_type, "image/jpeg") == 0)
|
||||||
free(url);
|
ret = ART_FMT_JPEG;
|
||||||
|
else if (strcmp(content_type, "image/png") == 0)
|
||||||
format_ok = 0;
|
ret = ART_FMT_PNG;
|
||||||
for (s = 0; s < src_ctx->nb_streams; s++)
|
|
||||||
{
|
|
||||||
if (src_ctx->streams[s]->codec->codec_id == AV_CODEC_ID_PNG)
|
|
||||||
{
|
|
||||||
format_ok = ART_FMT_PNG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (src_ctx->streams[s]->codec->codec_id == AV_CODEC_ID_MJPEG)
|
|
||||||
{
|
|
||||||
format_ok = ART_FMT_JPEG;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s == src_ctx->nb_streams)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_ART, "Artwork file '%s' not a PNG or JPEG file\n", path);
|
|
||||||
|
|
||||||
avformat_close_input(&src_ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
while (av_read_frame(src_ctx, &pkt) == 0)
|
|
||||||
{
|
|
||||||
if (pkt.stream_index != s)
|
|
||||||
{
|
|
||||||
av_free_packet(&pkt);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
DPRINTF(E_WARN, L_ART, "Could not read artwork: '%s'\n", path);
|
|
||||||
|
|
||||||
avformat_close_input(&src_ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = rescale_needed(src_ctx->streams[s]->codec, max_w, max_h, &target_w, &target_h);
|
|
||||||
|
|
||||||
/* Fastpath */
|
|
||||||
if (!ret && format_ok)
|
|
||||||
{
|
|
||||||
DPRINTF(E_DBG, L_ART, "Artwork not too large, using original image\n");
|
|
||||||
|
|
||||||
ret = evbuffer_expand(evbuf, pkt.size);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_ART, "Out of memory for artwork\n");
|
|
||||||
|
|
||||||
av_free_packet(&pkt);
|
|
||||||
avformat_close_input(&src_ctx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = evbuffer_add(evbuf, pkt.data, pkt.size);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_ART, "Could not add image to event buffer\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ret = format_ok;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
ret = 0;
|
||||||
DPRINTF(E_DBG, L_ART, "Artwork too large, rescaling image\n");
|
|
||||||
|
|
||||||
ret = artwork_rescale(src_ctx, s, target_w, target_h, evbuf);
|
if (ret)
|
||||||
}
|
DPRINTF(E_DBG, L_ART, "Found internet stream artwork in %s (%s)\n", url, content_type);
|
||||||
|
|
||||||
av_free_packet(&pkt);
|
keyval_clear(kv);
|
||||||
avformat_close_input(&src_ctx);
|
free(kv);
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
if (evbuffer_get_length(evbuf) > 0)
|
|
||||||
evbuffer_drain(evbuf, evbuffer_get_length(evbuf));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
/* ======================= libevent HTTP client =============================*/
|
/* ======================= libevent HTTP client =============================*/
|
||||||
|
|
||||||
// Number of seconds the client will wait for a response before aborting
|
// Number of seconds the client will wait for a response before aborting
|
||||||
#define HTTP_CLIENT_TIMEOUT 5
|
#define HTTP_CLIENT_TIMEOUT 8
|
||||||
|
|
||||||
/* The strict libevent api does not permit walking through an evkeyvalq and saving
|
/* The strict libevent api does not permit walking through an evkeyvalq and saving
|
||||||
* all the http headers, so we predefine what we are looking for. You can add
|
* all the http headers, so we predefine what we are looking for. You can add
|
||||||
@ -56,6 +56,7 @@ static char *header_list[] =
|
|||||||
"icy-description",
|
"icy-description",
|
||||||
"icy-metaint",
|
"icy-metaint",
|
||||||
"icy-genre",
|
"icy-genre",
|
||||||
|
"Content-Type",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Copies headers we are searching for from one keyval struct to another
|
/* Copies headers we are searching for from one keyval struct to another
|
||||||
@ -257,12 +258,12 @@ request_make(void *arg)
|
|||||||
evhttp_add_header(headers, "Icy-MetaData", "1");
|
evhttp_add_header(headers, "Icy-MetaData", "1");
|
||||||
|
|
||||||
/* Make request */
|
/* Make request */
|
||||||
DPRINTF(E_INFO, L_HTTP, "Making request to %s:%d\n", hostname, port);
|
DPRINTF(E_INFO, L_HTTP, "Making request for http://%s:%d%s\n", hostname, port, path);
|
||||||
|
|
||||||
ret = evhttp_make_request(evcon, req, EVHTTP_REQ_GET, path);
|
ret = evhttp_make_request(evcon, req, EVHTTP_REQ_GET, path);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_HTTP, "Error making http request to %s:%d\n", hostname, port);
|
DPRINTF(E_LOG, L_HTTP, "Error making request for http://%s:%d%s\n", hostname, port, path);
|
||||||
|
|
||||||
evhttp_connection_free(evcon);
|
evhttp_connection_free(evcon);
|
||||||
event_base_free(ctx->evbase);
|
event_base_free(ctx->evbase);
|
||||||
|
@ -12,7 +12,6 @@ struct http_client_ctx
|
|||||||
{
|
{
|
||||||
int async;
|
int async;
|
||||||
const char *url;
|
const char *url;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* For sync mode, a keyval/evbuf to store response headers and body
|
/* For sync mode, a keyval/evbuf to store response headers and body
|
||||||
* Can be set to NULL to ignore that part of the response
|
* Can be set to NULL to ignore that part of the response
|
||||||
@ -30,6 +29,7 @@ struct http_client_ctx
|
|||||||
void (*cb)(struct evhttp_request *, void *);
|
void (*cb)(struct evhttp_request *, void *);
|
||||||
|
|
||||||
/* Private */
|
/* Private */
|
||||||
|
int ret;
|
||||||
void *evbase;
|
void *evbase;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user