It allows attaching arbitrary files, e.g. fonts to Matroska 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 |