diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 5527dbe49b..b1876f7788 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -628,6 +628,8 @@ typedef struct OutputStream {
 } OutputStream;
 
 typedef struct OutputFile {
+    const AVClass *class;
+
     int index;
 
     const AVOutputFormat *format;
diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
index 20524e5a28..96d6747749 100644
--- a/fftools/ffmpeg_mux.c
+++ b/fftools/ffmpeg_mux.c
@@ -207,8 +207,7 @@ static void *muxer_thread(void *arg)
 
         ret = tq_receive(mux->tq, &stream_idx, pkt);
         if (stream_idx < 0) {
-            av_log(NULL, AV_LOG_VERBOSE,
-                   "All streams finished for output file #%d\n", of->index);
+            av_log(mux, AV_LOG_VERBOSE, "All streams finished\n");
             ret = 0;
             break;
         }
@@ -219,8 +218,7 @@ static void *muxer_thread(void *arg)
         if (ret == AVERROR_EOF)
             tq_receive_finish(mux->tq, stream_idx);
         else if (ret < 0) {
-            av_log(NULL, AV_LOG_ERROR,
-                   "Error muxing a packet for output file #%d\n", of->index);
+            av_log(mux, AV_LOG_ERROR, "Error muxing a packet\n");
             break;
         }
     }
@@ -231,7 +229,7 @@ finish:
     for (unsigned int i = 0; i < mux->fc->nb_streams; i++)
         tq_receive_finish(mux->tq, i);
 
-    av_log(NULL, AV_LOG_VERBOSE, "Terminating muxer thread %d\n", of->index);
+    av_log(mux, AV_LOG_VERBOSE, "Terminating muxer thread\n");
 
     return (void*)(intptr_t)ret;
 }
@@ -511,10 +509,8 @@ int mux_check_init(Muxer *mux)
 
     ret = avformat_write_header(fc, &mux->opts);
     if (ret < 0) {
-        av_log(NULL, AV_LOG_ERROR,
-               "Could not write header for output file #%d "
-               "(incorrect codec parameters ?): %s\n",
-               of->index, av_err2str(ret));
+        av_log(mux, AV_LOG_ERROR, "Could not write header (incorrect codec "
+               "parameters ?): %s\n", av_err2str(ret));
         return ret;
     }
     //assert_avoptions(of->opts);
@@ -604,10 +600,9 @@ int of_write_trailer(OutputFile *of)
     int ret;
 
     if (!mux->tq) {
-        av_log(NULL, AV_LOG_ERROR,
-               "Nothing was written into output file %d (%s), because "
-               "at least one of its streams received no packets.\n",
-               of->index, fc->url);
+        av_log(mux, AV_LOG_ERROR,
+               "Nothing was written into output file, because "
+               "at least one of its streams received no packets.\n");
         return AVERROR(EINVAL);
     }
 
@@ -617,7 +612,7 @@ int of_write_trailer(OutputFile *of)
 
     ret = av_write_trailer(fc);
     if (ret < 0) {
-        av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s\n", fc->url, av_err2str(ret));
+        av_log(mux, AV_LOG_ERROR, "Error writing trailer: %s\n", av_err2str(ret));
         return ret;
     }
 
@@ -626,8 +621,7 @@ int of_write_trailer(OutputFile *of)
     if (!(of->format->flags & AVFMT_NOFILE)) {
         ret = avio_closep(&fc->pb);
         if (ret < 0) {
-            av_log(NULL, AV_LOG_ERROR, "Error closing file %s: %s\n",
-                   fc->url, av_err2str(ret));
+            av_log(mux, AV_LOG_ERROR, "Error closing file: %s\n", av_err2str(ret));
             return ret;
         }
     }
diff --git a/fftools/ffmpeg_mux.h b/fftools/ffmpeg_mux.h
index 6a72b9dc91..8a90cc56c6 100644
--- a/fftools/ffmpeg_mux.h
+++ b/fftools/ffmpeg_mux.h
@@ -63,6 +63,9 @@ typedef struct MuxStream {
 typedef struct Muxer {
     OutputFile of;
 
+    // name used for logging
+    char log_name[32];
+
     AVFormatContext *fc;
 
     pthread_t    thread;
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 9eea8639dc..f543438b18 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -818,7 +818,7 @@ static void init_output_filter(OutputFilter *ofilter, const OptionsContext *o,
     case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(mux, o, NULL); break;
     case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(mux, o, NULL); break;
     default:
-        av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
+        av_log(mux, AV_LOG_FATAL, "Only video and audio filters are supported "
                "currently.\n");
         exit_program(1);
     }
@@ -1023,7 +1023,7 @@ static void map_manual(Muxer *mux, const OptionsContext *o, const StreamMap *map
         }
 loop_end:
         if (!ofilter) {
-            av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
+            av_log(mux, AV_LOG_FATAL, "Output with label '%s' does not exist "
                    "in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
             exit_program(1);
         }
@@ -1031,7 +1031,7 @@ loop_end:
     } else {
         ist = input_files[map->file_index]->streams[map->stream_index];
         if (ist->user_set_discard == AVDISCARD_ALL) {
-            av_log(NULL, AV_LOG_FATAL, "Stream #%d:%d is disabled and cannot be mapped.\n",
+            av_log(mux, AV_LOG_FATAL, "Stream #%d:%d is disabled and cannot be mapped.\n",
                    map->file_index, map->stream_index);
             exit_program(1);
         }
@@ -1056,11 +1056,11 @@ loop_end:
                 break;
             }
         default:
-            av_log(NULL, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL,
+            av_log(mux, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL,
                    "Cannot map stream #%d:%d - unsupported type.\n",
                    map->file_index, map->stream_index);
             if (!ignore_unknown_streams) {
-                av_log(NULL, AV_LOG_FATAL,
+                av_log(mux, AV_LOG_FATAL,
                        "If you want unsupported types ignored instead "
                        "of failing, please use the -ignore_unknown option\n"
                        "If you want them copied, please use -copy_unknown\n");
@@ -1082,18 +1082,18 @@ static void of_add_attachments(Muxer *mux, const OptionsContext *o)
         int64_t len;
 
         if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
-            av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
+            av_log(mux, AV_LOG_FATAL, "Could not open attachment file %s.\n",
                    o->attachments[i]);
             exit_program(1);
         }
         if ((len = avio_size(pb)) <= 0) {
-            av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
+            av_log(mux, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
                    o->attachments[i]);
             exit_program(1);
         }
         if (len > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE ||
             !(attachment = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE))) {
-            av_log(NULL, AV_LOG_FATAL, "Attachment %s too large.\n",
+            av_log(mux, AV_LOG_FATAL, "Attachment %s too large.\n",
                    o->attachments[i]);
             exit_program(1);
         }
@@ -1156,7 +1156,7 @@ static void create_streams(Muxer *mux, const OptionsContext *o)
 
     if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) {
         av_dump_format(oc, nb_output_files - 1, oc->url, 1);
-        av_log(NULL, AV_LOG_ERROR, "Output file #%d does not contain any stream\n", nb_output_files - 1);
+        av_log(mux, AV_LOG_ERROR, "Output file does not contain any stream\n");
         exit_program(1);
     }
 }
@@ -1255,8 +1255,9 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u
     return 0;
 }
 
-static void of_add_programs(AVFormatContext *oc, const OptionsContext *o)
+static void of_add_programs(Muxer *mux, const OptionsContext *o)
 {
+    AVFormatContext *oc = mux->fc;
     /* process manually set programs */
     for (int i = 0; i < o->nb_program; i++) {
         const char *p = o->program[i].u.str;
@@ -1301,7 +1302,7 @@ static void of_add_programs(AVFormatContext *oc, const OptionsContext *o)
 
             key = av_get_token(&p2, "=");
             if (!key) {
-                av_log(NULL, AV_LOG_FATAL,
+                av_log(mux, AV_LOG_FATAL,
                        "No '=' character in program string %s.\n",
                        p2);
                 exit_program(1);
@@ -1317,7 +1318,7 @@ static void of_add_programs(AVFormatContext *oc, const OptionsContext *o)
                 int st_num = strtol(p2, NULL, 0);
                 av_program_add_stream_index(oc, progid, st_num);
             } else {
-                av_log(NULL, AV_LOG_FATAL, "Unknown program key %s.\n", key);
+                av_log(mux, AV_LOG_FATAL, "Unknown program key %s.\n", key);
                 exit_program(1);
             }
             av_freep(&to_dealloc);
@@ -1333,7 +1334,8 @@ static void of_add_programs(AVFormatContext *oc, const OptionsContext *o)
  * @param index for type c/p, chapter/program index is written here
  * @param stream_spec for type s, the stream specifier is written here
  */
-static void parse_meta_type(const char *arg, char *type, int *index, const char **stream_spec)
+static void parse_meta_type(void *logctx, const char *arg,
+                            char *type, int *index, const char **stream_spec)
 {
     if (*arg) {
         *type = *arg;
@@ -1342,7 +1344,7 @@ static void parse_meta_type(const char *arg, char *type, int *index, const char
             break;
         case 's':
             if (*(++arg) && *arg != ':') {
-                av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
+                av_log(logctx, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
                 exit_program(1);
             }
             *stream_spec = *arg == ':' ? arg + 1 : "";
@@ -1353,7 +1355,7 @@ static void parse_meta_type(const char *arg, char *type, int *index, const char
                 *index = strtol(++arg, NULL, 0);
             break;
         default:
-            av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
+            av_log(logctx, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
             exit_program(1);
         }
     } else
@@ -1371,13 +1373,13 @@ static void of_add_metadata(OutputFile *of, AVFormatContext *oc,
 
         val = strchr(o->metadata[i].u.str, '=');
         if (!val) {
-            av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
+            av_log(of, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
                    o->metadata[i].u.str);
             exit_program(1);
         }
         *val++ = 0;
 
-        parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
+        parse_meta_type(of, o->metadata[i].specifier, &type, &index, &stream_spec);
         if (type == 's') {
             for (int j = 0; j < oc->nb_streams; j++) {
                 OutputStream *ost = of->streams[j];
@@ -1412,20 +1414,20 @@ static void of_add_metadata(OutputFile *of, AVFormatContext *oc,
                 break;
             case 'c':
                 if (index < 0 || index >= oc->nb_chapters) {
-                    av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
+                    av_log(of, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
                     exit_program(1);
                 }
                 m = &oc->chapters[index]->metadata;
                 break;
             case 'p':
                 if (index < 0 || index >= oc->nb_programs) {
-                    av_log(NULL, AV_LOG_FATAL, "Invalid program index %d in metadata specifier.\n", index);
+                    av_log(of, AV_LOG_FATAL, "Invalid program index %d in metadata specifier.\n", index);
                     exit_program(1);
                 }
                 m = &oc->programs[index]->metadata;
                 break;
             default:
-                av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
+                av_log(of, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
                 exit_program(1);
             }
             av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
@@ -1514,11 +1516,12 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, AVFormatContext *o
     return 0;
 }
 
-static int copy_metadata(const char *outspec, const char *inspec,
-                         AVFormatContext *oc, AVFormatContext *ic,
+static int copy_metadata(Muxer *mux, AVFormatContext *ic,
+                         const char *outspec, const char *inspec,
                          int *metadata_global_manual, int *metadata_streams_manual,
                          int *metadata_chapters_manual, const OptionsContext *o)
 {
+    AVFormatContext *oc = mux->fc;
     AVDictionary **meta_in = NULL;
     AVDictionary **meta_out = NULL;
     int i, ret = 0;
@@ -1526,8 +1529,8 @@ static int copy_metadata(const char *outspec, const char *inspec,
     const char *istream_spec = NULL, *ostream_spec = NULL;
     int idx_in = 0, idx_out = 0;
 
-    parse_meta_type(inspec,  &type_in,  &idx_in,  &istream_spec);
-    parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
+    parse_meta_type(mux, inspec,  &type_in,  &idx_in,  &istream_spec);
+    parse_meta_type(mux, outspec, &type_out, &idx_out, &ostream_spec);
 
     if (type_in == 'g' || type_out == 'g')
         *metadata_global_manual = 1;
@@ -1542,7 +1545,7 @@ static int copy_metadata(const char *outspec, const char *inspec,
 
 #define METADATA_CHECK_INDEX(index, nb_elems, desc)\
     if ((index) < 0 || (index) >= (nb_elems)) {\
-        av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
+        av_log(mux, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
                 (desc), (index));\
         exit_program(1);\
     }
@@ -1578,7 +1581,7 @@ static int copy_metadata(const char *outspec, const char *inspec,
                 exit_program(1);
         }
         if (!meta_in) {
-            av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match  any streams.\n", istream_spec);
+            av_log(mux, AV_LOG_FATAL, "Stream specifier %s does not match  any streams.\n", istream_spec);
             exit_program(1);
         }
     }
@@ -1612,12 +1615,13 @@ static void copy_meta(Muxer *mux, const OptionsContext *o)
         int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
 
         if (in_file_index >= nb_input_files) {
-            av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
+            av_log(mux, AV_LOG_FATAL, "Invalid input file index %d while "
+                   "processing metadata maps\n", in_file_index);
             exit_program(1);
         }
-        copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
-                      in_file_index >= 0 ?
-                      input_files[in_file_index]->ctx : NULL,
+        copy_metadata(mux,
+                      in_file_index >= 0 ? input_files[in_file_index]->ctx : NULL,
+                      o->metadata_map[i].specifier, *p ? p + 1 : p,
                       &metadata_global_manual, &metadata_streams_manual,
                       &metadata_chapters_manual, o);
     }
@@ -1633,7 +1637,7 @@ static void copy_meta(Muxer *mux, const OptionsContext *o)
                     break;
                 }
         } else {
-            av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
+            av_log(mux, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
                    chapters_input_file);
             exit_program(1);
         }
@@ -1854,7 +1858,7 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
     return 0;
 }
 
-static void validate_enc_avopt(const Muxer *mux, const AVDictionary *codec_avopt)
+static void validate_enc_avopt(Muxer *mux, const AVDictionary *codec_avopt)
 {
     const AVClass *class  = avcodec_get_class();
     const AVClass *fclass = avformat_get_class();
@@ -1880,10 +1884,8 @@ static void validate_enc_avopt(const Muxer *mux, const AVDictionary *codec_avopt
             continue;
 
         if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
-            av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
-                   "output file #%d (%s) is not an encoding option.\n", e->key,
-                   option->help ? option->help : "", nb_output_files - 1,
-                   mux->fc->url);
+            av_log(mux, AV_LOG_ERROR, "Codec AVOption %s (%s) is not an "
+                   "encoding option.\n", e->key, option->help ? option->help : "");
             exit_program(1);
         }
 
@@ -1891,16 +1893,41 @@ static void validate_enc_avopt(const Muxer *mux, const AVDictionary *codec_avopt
         if (!strcmp(e->key, "gop_timecode"))
             continue;
 
-        av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
-               "output file #%d (%s) has not been used for any stream. The most "
-               "likely reason is either wrong type (e.g. a video option with "
-               "no video streams) or that it is a private option of some encoder "
-               "which was not actually used for any stream.\n", e->key,
-               option->help ? option->help : "", nb_output_files - 1, mux->fc->url);
+        av_log(mux, AV_LOG_WARNING, "Codec AVOption %s (%s) has not been used "
+               "for any stream. The most likely reason is either wrong type "
+               "(e.g. a video option with no video streams) or that it is a "
+               "private option of some encoder which was not actually used for "
+               "any stream.\n", e->key, option->help ? option->help : "");
     }
     av_dict_free(&unused_opts);
 }
 
+static const char *output_file_item_name(void *obj)
+{
+    const Muxer *mux = obj;
+
+    return mux->log_name;
+}
+
+static const AVClass output_file_class = {
+    .class_name = "OutputFile",
+    .version    = LIBAVUTIL_VERSION_INT,
+    .item_name  = output_file_item_name,
+    .category   = AV_CLASS_CATEGORY_MUXER,
+};
+
+static Muxer *mux_alloc(void)
+{
+    Muxer *mux = allocate_array_elem(&output_files, sizeof(*mux), &nb_output_files);
+
+    mux->of.class = &output_file_class;
+    mux->of.index = nb_output_files - 1;
+
+    snprintf(mux->log_name, sizeof(mux->log_name), "out#%d", mux->of.index);
+
+    return mux;
+}
+
 int of_open(const OptionsContext *o, const char *filename)
 {
     Muxer *mux;
@@ -1911,25 +1938,24 @@ int of_open(const OptionsContext *o, const char *filename)
     int64_t recording_time = o->recording_time;
     int64_t stop_time      = o->stop_time;
 
+    mux = mux_alloc();
+    of  = &mux->of;
+
     if (stop_time != INT64_MAX && recording_time != INT64_MAX) {
         stop_time = INT64_MAX;
-        av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
+        av_log(mux, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
     }
 
     if (stop_time != INT64_MAX && recording_time == INT64_MAX) {
         int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;
         if (stop_time <= start_time) {
-            av_log(NULL, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n");
+            av_log(mux, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n");
             exit_program(1);
         } else {
             recording_time = stop_time - start_time;
         }
     }
 
-    mux = allocate_array_elem(&output_files, sizeof(Muxer), &nb_output_files);
-    of  = &mux->of;
-
-    of->index          = nb_output_files - 1;
     of->recording_time = recording_time;
     of->start_time     = o->start_time;
     of->shortest       = o->shortest;
@@ -1948,6 +1974,9 @@ int of_open(const OptionsContext *o, const char *filename)
     }
     mux->fc = oc;
 
+    av_strlcat(mux->log_name, "/",               sizeof(mux->log_name));
+    av_strlcat(mux->log_name, oc->oformat->name, sizeof(mux->log_name));
+
     if (strcmp(oc->oformat->name, "rtp"))
         want_sdp = 0;
 
@@ -2061,12 +2090,12 @@ int of_open(const OptionsContext *o, const char *filename)
     /* copy metadata and chapters from input files */
     copy_meta(mux, o);
 
-    of_add_programs(oc, o);
+    of_add_programs(mux, o);
     of_add_metadata(of, oc, o);
 
     err = set_dispositions(mux, o);
     if (err < 0) {
-        av_log(NULL, AV_LOG_FATAL, "Error setting output stream dispositions\n");
+        av_log(mux, AV_LOG_FATAL, "Error setting output stream dispositions\n");
         exit_program(1);
     }
 
@@ -2074,13 +2103,13 @@ int of_open(const OptionsContext *o, const char *filename)
     // must be done after chapters are created
     err = process_forced_keyframes(mux, o);
     if (err < 0) {
-        av_log(NULL, AV_LOG_FATAL, "Error processing forced keyframes\n");
+        av_log(mux, AV_LOG_FATAL, "Error processing forced keyframes\n");
         exit_program(1);
     }
 
     err = setup_sync_queues(mux, oc, o->shortest_buf_duration * AV_TIME_BASE);
     if (err < 0) {
-        av_log(NULL, AV_LOG_FATAL, "Error setting up output sync queues\n");
+        av_log(mux, AV_LOG_FATAL, "Error setting up output sync queues\n");
         exit_program(1);
     }
 
