aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-07-30 19:39:05 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-07-30 19:39:05 +0200
commit9b6fe48ffc63832125b519e7f839650a16d79804 (patch)
tree752092ec1273276789626f157abca75952d66c56
parent19caa87a466e02e53e91a97f1084d860b02de9eb (diff)
parent5f2817a40d509e9dc172a161ac1a3efb66b8e7b8 (diff)
downloadODR-AudioEnc-9b6fe48ffc63832125b519e7f839650a16d79804.tar.gz
ODR-AudioEnc-9b6fe48ffc63832125b519e7f839650a16d79804.tar.bz2
ODR-AudioEnc-9b6fe48ffc63832125b519e7f839650a16d79804.zip
Merge 'gh/next' into next
-rw-r--r--src/VLCInput.cpp55
-rw-r--r--src/VLCInput.h35
-rw-r--r--src/mot-encoder.cpp58
3 files changed, 117 insertions, 31 deletions
diff --git a/src/VLCInput.cpp b/src/VLCInput.cpp
index 9f0aa65..0ce4f00 100644
--- a/src/VLCInput.cpp
+++ b/src/VLCInput.cpp
@@ -324,17 +324,34 @@ ssize_t VLCInput::m_read(uint8_t* buf, size_t length)
break;
}
- char* nowplaying_sz = libvlc_media_get_meta(media, libvlc_meta_NowPlaying);
- if (nowplaying_sz) {
- std::lock_guard<std::mutex> lock(m_nowplaying_mutex);
- m_nowplaying = nowplaying_sz;
+ // handle meta data
+ char* artist_sz = libvlc_media_get_meta(media, libvlc_meta_Artist);
+ char* title_sz = libvlc_media_get_meta(media, libvlc_meta_Title);
- free(nowplaying_sz);
+ if (artist_sz && title_sz) {
+ // use Artist and Title
+ std::lock_guard<std::mutex> lock(m_nowplaying_mutex);
+ m_nowplaying.useArtistTitle(artist_sz, title_sz);
+ } else {
+ // try fallback to NowPlaying
+ char* nowplaying_sz = libvlc_media_get_meta(media, libvlc_meta_NowPlaying);
+ if (nowplaying_sz) {
+ std::lock_guard<std::mutex> lock(m_nowplaying_mutex);
+ m_nowplaying.useNowPlaying(nowplaying_sz);
+ free(nowplaying_sz);
+ }
}
+
+ if (artist_sz)
+ free(artist_sz);
+ if (title_sz)
+ free(title_sz);
}
return err;
}
+const std::string VLCInput::ICY_TEXT_SEPARATOR = " - ";
+
/*! Write the corresponding text to a file readable by mot-encoder, with optional
* DL+ information. The text is passed as a copy because we actually use the
* m_nowplaying variable which is also accessed in another thread, so better
@@ -342,11 +359,12 @@ ssize_t VLCInput::m_read(uint8_t* buf, size_t length)
*
* \return false on failure
*/
-bool write_icy_to_file(const std::string text, const std::string& filename, bool dl_plus)
+bool write_icy_to_file(const ICY_TEXT_T text, const std::string& filename, bool dl_plus)
{
FILE* fd = fopen(filename.c_str(), "wb");
if (fd) {
bool ret = true;
+ bool artist_title_used = !text.artist.empty() && !text.title.empty();
// if desired, prepend DL Plus information
if (dl_plus) {
@@ -354,15 +372,32 @@ bool write_icy_to_file(const std::string text, const std::string& filename, bool
ss << "##### parameters { #####\n";
ss << "DL_PLUS=1\n";
- // if non-empty text, add PROGRAMME.NOW tag
- if (!text.empty())
- ss << "DL_PLUS_TAG=33 0 " << (strlen_utf8(text.c_str()) - 1) << "\n"; // -1 !
+ // if non-empty text, add tag
+ if (artist_title_used) {
+ size_t artist_len = strlen_utf8(text.artist.c_str());
+ size_t title_start = artist_len + strlen_utf8(VLCInput::ICY_TEXT_SEPARATOR.c_str());
+
+ // ITEM.ARTIST
+ ss << "DL_PLUS_TAG=4 0 " << (artist_len - 1) << "\n"; // -1 !
+
+ // ITEM.TITLE
+ ss << "DL_PLUS_TAG=1 " << title_start << " " << (strlen_utf8(text.title.c_str()) - 1) << "\n"; // -1 !
+ } else if (!text.now_playing.empty()) {
+ // PROGRAMME.NOW
+ ss << "DL_PLUS_TAG=33 0 " << (strlen_utf8(text.now_playing.c_str()) - 1) << "\n"; // -1 !
+ }
ss << "##### parameters } #####\n";
ret &= fputs(ss.str().c_str(), fd) >= 0;
}
- ret &= fputs(text.c_str(), fd) >= 0;
+ if (artist_title_used) {
+ ret &= fputs(text.artist.c_str(), fd) >= 0;
+ ret &= fputs(VLCInput::ICY_TEXT_SEPARATOR.c_str(), fd) >= 0;
+ ret &= fputs(text.title.c_str(), fd) >= 0;
+ } else {
+ ret &= fputs(text.now_playing.c_str(), fd) >= 0;
+ }
fclose(fd);
return ret;
diff --git a/src/VLCInput.h b/src/VLCInput.h
index 761492b..da4b7ae 100644
--- a/src/VLCInput.h
+++ b/src/VLCInput.h
@@ -49,6 +49,34 @@ extern "C" {
/*! Common functionality for the direct libvlc input and the
* threaded libvlc input
*/
+
+struct ICY_TEXT_T {
+ std::string artist;
+ std::string title;
+ std::string now_playing;
+
+ bool operator==(const ICY_TEXT_T& other) const {
+ return
+ artist == other.artist &&
+ title == other.title &&
+ now_playing == other.now_playing;
+ }
+ bool operator!=(const ICY_TEXT_T& other) const {
+ return !(*this == other);
+ }
+ void useArtistTitle(std::string artist, std::string title) {
+ this->artist = artist;
+ this->title = title;
+ now_playing = "";
+ }
+ void useNowPlaying(std::string now_playing) {
+ artist = "";
+ title = "";
+ this->now_playing = now_playing;
+ }
+};
+
+
class VLCInput
{
public:
@@ -119,6 +147,9 @@ class VLCInput
bool fault_detected() { return m_fault; };
+ /*! Separator string used when artist/title are written
+ */
+ static const std::string ICY_TEXT_SEPARATOR;
private:
/*! Stop the player and release resources
*/
@@ -160,8 +191,8 @@ class VLCInput
*/
std::future<bool> icy_text_written;
std::mutex m_nowplaying_mutex;
- std::string m_nowplaying;
- std::string m_nowplaying_previous;
+ ICY_TEXT_T m_nowplaying;
+ ICY_TEXT_T m_nowplaying_previous;
// VLC pointers
libvlc_instance_t *m_vlc;
diff --git a/src/mot-encoder.cpp b/src/mot-encoder.cpp
index 8393bb7..b17c74d 100644
--- a/src/mot-encoder.cpp
+++ b/src/mot-encoder.cpp
@@ -1067,9 +1067,13 @@ void warnOnSmallerImage(size_t height, size_t width, std::string& fname) {
* \return the blobsize
*/
#if HAVE_MAGICKWAND
-size_t resizeImage(MagickWand* m_wand, unsigned char** blob, std::string& fname)
+size_t resizeImage(MagickWand* m_wand, unsigned char** blob, std::string& fname, bool* jfif_not_png)
{
- size_t blobsize;
+ unsigned char* blob_png;
+ unsigned char* blob_jpg;
+ size_t blobsize_png;
+ size_t blobsize_jpg;
+
size_t height = MagickGetImageHeight(m_wand);
size_t width = MagickGetImageWidth(m_wand);
@@ -1088,33 +1092,52 @@ size_t resizeImage(MagickWand* m_wand, unsigned char** blob, std::string& fname)
height = MagickGetImageHeight(m_wand);
width = MagickGetImageWidth(m_wand);
- MagickSetImageFormat(m_wand, "jpg");
+ // try PNG (zlib level 9 / possibly adaptive filtering)
+ MagickSetImageFormat(m_wand, "png");
+ MagickSetImageCompressionQuality(m_wand, 95);
+ blob_png = MagickGetImageBlob(m_wand, &blobsize_png);
- int quality = 100;
+ // try JPG
+ MagickSetImageFormat(m_wand, "jpg");
+ blob_jpg = NULL;
+ int quality_jpg = 100;
do {
- quality -= 5;
+ free(blob_jpg);
+ quality_jpg -= 5;
- MagickSetImageCompressionQuality(m_wand, quality);
- *blob = MagickGetImagesBlob(m_wand, &blobsize);
- } while (blobsize > MAXSLIDESIZE && quality > MINQUALITY);
+ MagickSetImageCompressionQuality(m_wand, quality_jpg);
+ blob_jpg = MagickGetImageBlob(m_wand, &blobsize_jpg);
+ } while (blobsize_jpg > MAXSLIDESIZE && quality_jpg > MINQUALITY);
- if (blobsize > MAXSLIDESIZE) {
- fprintf(stderr, "mot-encoder: Image Size too large after compression: %zu bytes\n",
- blobsize);
+ // check for max size
+ if (blobsize_png > MAXSLIDESIZE && blobsize_jpg > MAXSLIDESIZE) {
+ fprintf(stderr, "mot-encoder: Image Size too large after compression: %zu bytes (PNG), %zu bytes (JPEG)\n",
+ blobsize_png, blobsize_jpg);
+ free(blob_png);
+ free(blob_jpg);
return 0;
}
+ // choose the smaller one (at least one does not exceed the max size)
+ *jfif_not_png = blobsize_jpg < blobsize_png;
+
if (verbose) {
- fprintf(stderr, "mot-encoder resized image to %zu x %zu. Size after compression %zu bytes (q=%d)\n",
- width, height, blobsize, quality);
+ if (*jfif_not_png)
+ fprintf(stderr, "mot-encoder resized image to %zu x %zu. Size after compression %zu bytes (JPEG, q=%d; PNG was %zu bytes)\n",
+ width, height, blobsize_jpg, quality_jpg, blobsize_png);
+ else
+ fprintf(stderr, "mot-encoder resized image to %zu x %zu. Size after compression %zu bytes (PNG; JPEG was %zu bytes)\n",
+ width, height, blobsize_png, blobsize_jpg);
}
// warn if resized image smaller than default dimension
warnOnSmallerImage(height, width, fname);
- return blobsize;
+ free(*jfif_not_png ? blob_png : blob_jpg);
+ *blob = *jfif_not_png ? blob_jpg : blob_png;
+ return *jfif_not_png ? blobsize_jpg : blobsize_png;
}
#endif
@@ -1222,7 +1245,7 @@ int encodeFile(int output_fd, std::string& fname, int fidx, bool raw_slides)
if ((orig_is_jpeg || orig_is_png) && height <= 240 && width <= 320 && not jpeg_progr) {
// Don't recompress the image and check if the blobsize is suitable
- blob = MagickGetImagesBlob(m_wand, &blobsize);
+ blob = MagickGetImageBlob(m_wand, &blobsize);
if (blobsize <= MAXSLIDESIZE) {
if (verbose) {
@@ -1234,10 +1257,7 @@ int encodeFile(int output_fd, std::string& fname, int fidx, bool raw_slides)
}
if (resize_required) {
- blobsize = resizeImage(m_wand, &blob, fname);
-
- // resizeImage always creates a jpg output
- jfif_not_png = true;
+ blobsize = resizeImage(m_wand, &blob, fname, &jfif_not_png);
}
else {
// warn if unresized image smaller than default dimension