Ticket #4566: propagate-metadata-changes-to-icecast-outputs.patch
| File propagate-metadata-changes-to-icecast-outputs.patch, 6.9 KB (added by , 3 years ago) |
|---|
-
fftools/ffmpeg.c
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index e7384f052a..ba89270092 100644
a b static int transcode(void) 4341 4341 av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n"); 4342 4342 } 4343 4343 4344 // check if metadata propagation is required 4345 int propagate_metadata_updates = 0; 4346 for (i = 0; i < nb_output_files; i++) { 4347 if (strncmp(output_files[i]->ctx->url, "icecast://", 10) == 0) { 4348 propagate_metadata_updates = 1; 4349 break; 4350 } 4351 } 4352 4344 4353 timer_start = av_gettime_relative(); 4345 4354 4346 4355 #if HAVE_THREADS … … static int transcode(void) 4370 4379 4371 4380 /* dump report by using the output first video and audio streams */ 4372 4381 print_report(0, timer_start, cur_time); 4382 4383 for (i = 0; i < nb_input_streams && propagate_metadata_updates; i++) { 4384 ist = input_streams[i]; 4385 if (input_files[ist->file_index]->ctx->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) { 4386 input_files[ist->file_index]->ctx->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED; 4387 av_log(NULL, AV_LOG_TRACE, "Input metadata update detected on stream: %d\n", ist->file_index); 4388 for (i = 0; i < nb_output_files; i++) { 4389 av_dict_copy(&output_files[i]->ctx->metadata, input_files[ist->file_index]->ctx->metadata, 0); 4390 output_files[i]->ctx->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; 4391 } 4392 } 4393 } 4373 4394 } 4374 4395 #if HAVE_THREADS 4375 4396 free_input_threads(); -
fftools/ffmpeg_opt.c
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 6e18a4a23e..c0ca635fda 100644
a b 33 33 #include "opt_common.h" 34 34 35 35 #include "libavformat/avformat.h" 36 #include "libavformat/url.h" 36 37 37 38 #include "libavcodec/avcodec.h" 38 39 #include "libavcodec/bsf.h" … … loop_end: 2845 2846 print_error(filename, err); 2846 2847 exit_program(1); 2847 2848 } 2849 // set the AVFormatContext parent reference in URLContext 2850 if (strncmp(oc->url, "icecast://", 10) == 0) { 2851 av_log(NULL, AV_LOG_TRACE, "Set AVFormatContext parent reference in URLContext\n"); 2852 ((URLContext *)oc->pb->opaque)->ctx = oc; 2853 } 2848 2854 } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename)) 2849 2855 assert_file_overwrite(filename); 2850 2856 -
libavformat/icecast.c
diff --git a/libavformat/icecast.c b/libavformat/icecast.c index b06c53cabd..2524688255 100644
a b typedef struct IcecastContext { 33 33 URLContext *hd; 34 34 int send_started; 35 35 char *user; 36 char *metadata_url; 36 37 // Options 37 38 char *content_type; 38 39 char *description; … … static int icecast_open(URLContext *h, const char *uri, int flags) 163 164 goto cleanup; 164 165 } 165 166 167 // Build URI for metadata updates 168 ff_url_join(h_url, sizeof(h_url), 169 s->tls ? "https" : "http", 170 auth, host, port, "/admin/metadata?mode=updinfo&charset=UTF-8&mount=%s", path); 171 s->metadata_url = av_strdup(h_url); 172 166 173 // Build new URI for passing to http protocol 167 174 ff_url_join(h_url, sizeof(h_url), 168 175 s->tls ? "https" : "http", … … cleanup: 178 185 return ret; 179 186 } 180 187 188 static int metadata_update_interrupt_cb(void *ctx) { 189 return 0; 190 } 191 192 const AVIOInterruptCB icecast_metadata_int_cb = { metadata_update_interrupt_cb, NULL }; 193 194 // escape the song name (like bprint_escaped_path but also escapes '&' and '#') 195 static void escape_metadata(char *buffer, int size, const char *song) { 196 #define NEEDS_ESCAPE(ch) \ 197 ((ch) <= ' ' || (ch) >= '\x7f' || \ 198 (ch) == '"' || (ch) == '%' || (ch) == '<' || (ch) == '>' || (ch) == '\\' || \ 199 (ch) == '^' || (ch) == '`' || (ch) == '{' || (ch) == '}' || (ch) == '|' || \ 200 (ch) == '&' || (ch) == '#') 201 char *q = buffer; 202 while (*song && q - buffer < size - 4) { 203 if (song[0] == '%' && av_isxdigit(song[1]) && av_isxdigit(song[2])) { 204 *q++ = *song++; 205 *q++ = *song++; 206 *q++ = *song++; 207 } else if (NEEDS_ESCAPE(*song)) { 208 q += snprintf(q, 4, "%%%02X", (uint8_t)*song++); 209 } else { 210 *q++ = *song++; 211 } 212 } 213 // terminate the string 214 if (q - buffer < size) { 215 *q = '\0'; 216 } else { 217 buffer[size - 1] = '\0'; 218 } 219 } 220 221 static void update_metadata(IcecastContext *s, const char *song) { 222 // escape the song name 223 char escaped_song[1024]; 224 escape_metadata(&escaped_song, sizeof(escaped_song), song); 225 226 // build the metadata update url 227 char h_url[2048]; 228 snprintf(h_url, sizeof(h_url), "%s&song=%s", s->metadata_url, &escaped_song); 229 av_log(s, AV_LOG_TRACE, "StreamTitle update: '%s', url: '%s'\n", song, h_url); 230 231 // call the metadata update url 232 AVDictionary *opt_dict = NULL; 233 av_dict_set(&opt_dict, "auth_type", "basic", 0); 234 if (NOT_EMPTY(s->user_agent)) 235 av_dict_set(&opt_dict, "user_agent", s->user_agent, 0); 236 AVIOContext *avio = NULL; 237 int ret = avio_open2(&avio, h_url, AVIO_FLAG_READ, &icecast_metadata_int_cb, &opt_dict); 238 if (ret < 0) { 239 av_log(NULL, AV_LOG_WARNING, "Failed to open metadata update URL \"%s\": %s\n", h_url, av_err2str(ret)); 240 } 241 if ((ret = avio_closep(&avio)) < 0) { 242 av_log(NULL, AV_LOG_ERROR, "Error closing metadata update URL \"%s\": %s\n", h_url, av_err2str(ret)); 243 } 244 av_dict_free(&opt_dict); 245 } 246 181 247 static int icecast_write(URLContext *h, const uint8_t *buf, int size) 182 248 { 183 249 IcecastContext *s = h->priv_data; … … static int icecast_write(URLContext *h, const uint8_t *buf, int size) 202 268 } 203 269 } 204 270 } 271 if (h->ctx && h->ctx->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) { 272 h->ctx->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED; 273 AVDictionaryEntry *song_entry = av_dict_get(h->ctx->metadata, "StreamTitle", NULL, 0); 274 if (song_entry) { 275 update_metadata(s, song_entry->value); 276 } 277 } 205 278 return ffurl_write(s->hd, buf, size); 206 279 } 207 280 -
libavformat/url.h
diff --git a/libavformat/url.h b/libavformat/url.h index 3cfe3ecc5c..c5f13fbb59 100644
a b 33 33 #define URL_PROTOCOL_FLAG_NETWORK 2 /*< The protocol uses network */ 34 34 35 35 extern const AVClass ffurl_context_class; 36 typedef struct AVFormatContext AVFormatContext; 36 37 37 38 typedef struct URLContext { 38 39 const AVClass *av_class; /**< information for av_log(). Set by url_open(). */ … … typedef struct URLContext { 48 49 const char *protocol_whitelist; 49 50 const char *protocol_blacklist; 50 51 int min_packet_size; /**< if non zero, the stream is packetized with this min packet size */ 52 AVFormatContext *ctx; /**< reference to the format context */ 51 53 } URLContext; 52 54 53 55 typedef struct URLProtocol {
