Libav 10 (and ffmpeg) now has native support for ICY metadata
This commit is contained in:
parent
b566c41a36
commit
116289f5b7
|
@ -525,7 +525,11 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct
|
||||||
else if (type & F_SCAN_TYPE_URL)
|
else if (type & F_SCAN_TYPE_URL)
|
||||||
{
|
{
|
||||||
mfi->data_kind = 1; /* url/stream */
|
mfi->data_kind = 1; /* url/stream */
|
||||||
|
#if LIBAVFORMAT_VERSION_MAJOR >= 56 || (LIBAVFORMAT_VERSION_MAJOR == 55 && LIBAVFORMAT_VERSION_MINOR >= 13)
|
||||||
|
ret = scan_metadata_ffmpeg(path, mfi);
|
||||||
|
#else
|
||||||
ret = scan_metadata_icy(path, mfi);
|
ret = scan_metadata_icy(path, mfi);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (type & F_SCAN_TYPE_SPOTIFY)
|
else if (type & F_SCAN_TYPE_SPOTIFY)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "filescanner.h"
|
#include "filescanner.h"
|
||||||
|
@ -313,10 +314,82 @@ extract_metadata(struct media_file_info *mfi, AVFormatContext *ctx, AVStream *au
|
||||||
return mdcount;
|
return mdcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Extracts ICY metadata (requires libav 10: libavformat 55.13) */
|
||||||
|
static void
|
||||||
|
extract_metadata_icy(struct media_file_info *mfi, AVFormatContext *ctx)
|
||||||
|
{
|
||||||
|
uint8_t *icy_meta;
|
||||||
|
char *icy_token;
|
||||||
|
char *icy_str;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
icy_meta = NULL;
|
||||||
|
// TODO Also get icy_metadata_packet to show current track
|
||||||
|
av_opt_get(ctx, "icy_metadata_headers", AV_OPT_SEARCH_CHILDREN, &icy_meta);
|
||||||
|
|
||||||
|
if (!icy_meta)
|
||||||
|
return;
|
||||||
|
|
||||||
|
icy_str = strdup((char *)icy_meta);
|
||||||
|
icy_token = strtok(icy_str, "\r\n");
|
||||||
|
|
||||||
|
while (icy_token != NULL)
|
||||||
|
{
|
||||||
|
ptr = strchr(icy_token, ':');
|
||||||
|
if (!ptr || (strlen(ptr) < 3))
|
||||||
|
icy_token = strtok(NULL, "\r\n");
|
||||||
|
|
||||||
|
ptr++;
|
||||||
|
if (ptr[0] == ' ')
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
if (strstr(icy_token, "icy-name"))
|
||||||
|
{
|
||||||
|
DPRINTF(E_DBG, L_SCAN, "Libav/ffmpeg found ICY metadata, name is '%s'\n", ptr);
|
||||||
|
|
||||||
|
if (mfi->title)
|
||||||
|
free(mfi->title);
|
||||||
|
if (mfi->artist)
|
||||||
|
free(mfi->artist);
|
||||||
|
if (mfi->album_artist)
|
||||||
|
free(mfi->album_artist);
|
||||||
|
|
||||||
|
mfi->title = strdup(ptr);
|
||||||
|
mfi->artist = strdup(ptr);
|
||||||
|
mfi->album_artist = strdup(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(icy_token, "icy-description"))
|
||||||
|
{
|
||||||
|
DPRINTF(E_DBG, L_SCAN, "Libav/ffmpeg found ICY metadata, description is '%s'\n", ptr);
|
||||||
|
|
||||||
|
if (mfi->album)
|
||||||
|
free(mfi->album);
|
||||||
|
|
||||||
|
mfi->album = strdup(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(icy_token, "icy-genre"))
|
||||||
|
{
|
||||||
|
DPRINTF(E_DBG, L_SCAN, "Libav/ffmpeg found ICY metadata, genre is '%s'\n", ptr);
|
||||||
|
|
||||||
|
if (mfi->genre)
|
||||||
|
free(mfi->genre);
|
||||||
|
|
||||||
|
mfi->genre = strdup(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
icy_token = strtok(NULL, "\r\n");
|
||||||
|
}
|
||||||
|
av_free(icy_meta);
|
||||||
|
free(icy_str);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
||||||
{
|
{
|
||||||
AVFormatContext *ctx;
|
AVFormatContext *ctx;
|
||||||
|
AVDictionary *options;
|
||||||
const struct metadata_map *extra_md_map;
|
const struct metadata_map *extra_md_map;
|
||||||
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
|
#if LIBAVCODEC_VERSION_MAJOR >= 55 || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 35)
|
||||||
enum AVCodecID codec_id;
|
enum AVCodecID codec_id;
|
||||||
|
@ -334,9 +407,13 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ctx = NULL;
|
ctx = NULL;
|
||||||
|
options = NULL;
|
||||||
|
|
||||||
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3)
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3)
|
||||||
ret = avformat_open_input(&ctx, file, NULL, NULL);
|
if (mfi->data_kind == 1)
|
||||||
|
av_dict_set(&options, "icy", "1", 0);
|
||||||
|
|
||||||
|
ret = avformat_open_input(&ctx, file, NULL, &options);
|
||||||
#else
|
#else
|
||||||
ret = av_open_input_file(&ctx, file, NULL, 0, NULL);
|
ret = av_open_input_file(&ctx, file, NULL, 0, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
@ -462,6 +539,10 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_SCAN, "Duration %d ms, bitrate %d kbps\n", mfi->song_length, mfi->bitrate);
|
DPRINTF(E_DBG, L_SCAN, "Duration %d ms, bitrate %d kbps\n", mfi->song_length, mfi->bitrate);
|
||||||
|
|
||||||
|
/* Try to extract ICY metadata if url/stream */
|
||||||
|
if (mfi->data_kind == 1)
|
||||||
|
extract_metadata_icy(mfi, ctx);
|
||||||
|
|
||||||
/* Get some more information on the audio stream */
|
/* Get some more information on the audio stream */
|
||||||
if (audio_stream)
|
if (audio_stream)
|
||||||
{
|
{
|
||||||
|
|
|
@ -244,7 +244,7 @@ scan_metadata_icy(char *url, struct media_file_info *mfi)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBEVENT2_OLD
|
#ifdef HAVE_LIBEVENT2_OLD
|
||||||
DPRINTF(E_LOG, L_SCAN, "Skipping Shoutcast metadata request for %s (requires libevent>=2.1.4)\n", ctx->hostname);
|
DPRINTF(E_LOG, L_SCAN, "Skipping Shoutcast metadata request for %s (requires libevent>=2.1.4 or libav 10)\n", ctx->hostname);
|
||||||
#else
|
#else
|
||||||
evhttp_connection_set_timeout(evcon, ICY_TIMEOUT);
|
evhttp_connection_set_timeout(evcon, ICY_TIMEOUT);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue