Browse code

avconv: add -attach option.

It allows attaching arbitrary files, e.g. fonts to Matroska files.

Anton Khirnov authored on 2011/10/30 15:10:08
Showing 2 changed files
... ...
@@ -228,6 +228,7 @@ typedef struct OutputStream {
228 228
    AVDictionary *opts;
229 229
    int is_past_recording_time;
230 230
    int stream_copy;
231
+   const char *attachment_filename;
231 232
 } OutputStream;
232 233
 
233 234
 
... ...
@@ -284,6 +285,8 @@ typedef struct OptionsContext {
284 284
     int metadata_global_manual;
285 285
     int metadata_streams_manual;
286 286
     int metadata_chapters_manual;
287
+    const char **attachments;
288
+    int       nb_attachments;
287 289
 
288 290
     int chapters_input_file;
289 291
 
... ...
@@ -1981,6 +1984,9 @@ static int transcode_init(OutputFile *output_files,
1981 1981
         os = output_files[ost->file_index].ctx;
1982 1982
         ist = &input_streams[ost->source_index];
1983 1983
 
1984
+        if (ost->attachment_filename)
1985
+            continue;
1986
+
1984 1987
         codec = ost->st->codec;
1985 1988
         icodec = ist->st->codec;
1986 1989
 
... ...
@@ -2286,6 +2292,13 @@ static int transcode_init(OutputFile *output_files,
2286 2286
     av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");
2287 2287
     for (i = 0; i < nb_output_streams; i++) {
2288 2288
         ost = &output_streams[i];
2289
+
2290
+        if (ost->attachment_filename) {
2291
+            /* an attached file */
2292
+            av_log(NULL, AV_LOG_INFO, "  File %s -> Stream #%d:%d\n",
2293
+                   ost->attachment_filename, ost->file_index, ost->index);
2294
+            continue;
2295
+        }
2289 2296
         av_log(NULL, AV_LOG_INFO, "  Stream #%d.%d -> #%d.%d",
2290 2297
                input_streams[ost->source_index].file_index,
2291 2298
                input_streams[ost->source_index].st->index,
... ...
@@ -2674,6 +2687,14 @@ static int opt_map(OptionsContext *o, const char *opt, const char *arg)
2674 2674
     return 0;
2675 2675
 }
2676 2676
 
2677
+static int opt_attach(OptionsContext *o, const char *opt, const char *arg)
2678
+{
2679
+    o->attachments = grow_array(o->attachments, sizeof(*o->attachments),
2680
+                                &o->nb_attachments, o->nb_attachments + 1);
2681
+    o->attachments[o->nb_attachments - 1] = arg;
2682
+    return 0;
2683
+}
2684
+
2677 2685
 static void parse_meta_type(char *arg, char *type, int *index)
2678 2686
 {
2679 2687
     if (*arg) {
... ...
@@ -3527,6 +3548,42 @@ static void opt_output_file(void *optctx, const char *filename)
3527 3527
         }
3528 3528
     }
3529 3529
 
3530
+    /* handle attached files */
3531
+    for (i = 0; i < o->nb_attachments; i++) {
3532
+        AVIOContext *pb;
3533
+        uint8_t *attachment;
3534
+        const char *p;
3535
+        int64_t len;
3536
+
3537
+        if ((err = avio_open(&pb, o->attachments[i], AVIO_FLAG_READ)) < 0) {
3538
+            av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
3539
+                   o->attachments[i]);
3540
+            exit_program(1);
3541
+        }
3542
+        if ((len = avio_size(pb)) <= 0) {
3543
+            av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
3544
+                   o->attachments[i]);
3545
+            exit_program(1);
3546
+        }
3547
+        if (!(attachment = av_malloc(len))) {
3548
+            av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
3549
+                   o->attachments[i]);
3550
+            exit_program(1);
3551
+        }
3552
+        avio_read(pb, attachment, len);
3553
+
3554
+        ost = new_attachment_stream(o, oc);
3555
+        ost->stream_copy               = 0;
3556
+        ost->source_index              = -1;
3557
+        ost->attachment_filename       = o->attachments[i];
3558
+        ost->st->codec->extradata      = attachment;
3559
+        ost->st->codec->extradata_size = len;
3560
+
3561
+        p = strrchr(o->attachments[i], '/');
3562
+        av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
3563
+        avio_close(pb);
3564
+    }
3565
+
3530 3566
     output_files = grow_array(output_files, sizeof(*output_files), &nb_output_files, nb_output_files + 1);
3531 3567
     output_files[nb_output_files - 1].ctx       = oc;
3532 3568
     output_files[nb_output_files - 1].ost_index = nb_output_streams - oc->nb_streams;
... ...
@@ -3652,7 +3709,10 @@ static void opt_output_file(void *optctx, const char *filename)
3652 3652
                      AV_DICT_DONT_OVERWRITE);
3653 3653
     if (!o->metadata_streams_manual)
3654 3654
         for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) {
3655
-            InputStream *ist = &input_streams[output_streams[i].source_index];
3655
+            InputStream *ist;
3656
+            if (output_streams[i].source_index < 0)         /* this is true e.g. for attached files */
3657
+                continue;
3658
+            ist = &input_streams[output_streams[i].source_index];
3656 3659
             av_dict_copy(&output_streams[i].st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
3657 3660
         }
3658 3661
 
... ...
@@ -4025,6 +4085,7 @@ static const OptionDef options[] = {
4025 4025
     { "filter", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(filters)}, "set stream filterchain", "filter_list" },
4026 4026
 #endif
4027 4027
     { "stats", OPT_BOOL, {&print_stats}, "print progress report during encoding", },
4028
+    { "attach", HAS_ARG | OPT_FUNC2, {(void*)opt_attach}, "add an attachment to the output file", "filename" },
4028 4029
 
4029 4030
     /* video options */
4030 4031
     { "vframes", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_frames}, "set the number of video frames to record", "number" },
... ...
@@ -192,6 +192,21 @@ Specify the preset for matching stream(s).
192 192
 @item -stats (@emph{global})
193 193
 Print encoding progress/statistics. On by default.
194 194
 
195
+@item -attach @var{filename} (@emph{output})
196
+Add an attachment to the output file. This is supported by a few formats
197
+like Matroska for e.g. fonts used in rendering subtitles. Attachments
198
+are implemented as a specific type of stream, so this option will add
199
+a new stream to the file. It is then possible to use per-stream options
200
+on this stream in the usual way. Attachment streams created with this
201
+option will be created after all the other streams (i.e. those created
202
+with @code{-map} or automatic mappings).
203
+
204
+Note that for Matroska you also have to set the mimetype metadata tag:
205
+@example
206
+avconv -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
207
+@end example
208
+(assuming that the attachment stream will be third in the output file).
209
+
195 210
 @end table
196 211
 
197 212
 @section Video Options