act, bintext, wtvenc: use named struct initializers
[ffmpeg.git] / libavformat / wtvenc.c
1 /*
2  * Windows Television (WTV) muxer
3  * Copyright (c) 2011 Zhentan Feng <spyfeng at gmail dot com>
4  * Copyright (c) 2011 Peter Ross <pross@xvid.org>
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/avassert.h"
24 #include "avformat.h"
25 #include "internal.h"
26 #include "wtv.h"
27
28 #define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS)
29 #define INDEX_BASE 0x2
30 #define MAX_NB_INDEX 10
31
32 /* declare utf16le strings */
33 #define _ , 0,
34 static const uint8_t timeline_table_0_header_events[] =
35     {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0};
36 static const uint8_t table_0_header_legacy_attrib[] =
37     {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
38 static const uint8_t table_0_redirector_legacy_attrib[] =
39     {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'r'_'e'_'d'_'i'_'r'_'e'_'c'_'t'_'o'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
40 static const uint8_t table_0_header_time[] =
41     {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'t'_'i'_'m'_'e', 0};
42 static const uint8_t legacy_attrib[] =
43     {'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
44 #undef _
45
46 static const ff_asf_guid sub_wtv_guid =
47     {0x8C,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
48 static const ff_asf_guid stream1_guid =
49     {0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
50 static const ff_asf_guid sync_guid =
51     {0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
52 static const ff_asf_guid index_guid =
53     {0x96,0xc3,0xd2,0xc2,0x7e,0x9a,0xda,0x11,0x8b,0xf7,0x00,0x07,0xe9,0x5e,0xad,0x8d};
54
55 enum WtvFileIndex {
56     WTV_TIMELINE_TABLE_0_HEADER_EVENTS = 0,
57     WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS,
58     WTV_TIMELINE,
59     WTV_TABLE_0_HEADER_LEGACY_ATTRIB,
60     WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB,
61     WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB,
62     WTV_TABLE_0_HEADER_TIME,
63     WTV_TABLE_0_ENTRIES_TIME,
64     WTV_FILES
65 };
66
67 typedef struct {
68     int64_t length;
69     const void *header;
70     int depth;
71     int first_sector;
72 } WtvFile;
73
74 typedef struct {
75     int64_t             pos;
76     int64_t             serial;
77     const ff_asf_guid * guid;
78     int                 stream_id;
79 } WtvChunkEntry;
80
81 typedef struct {
82     int64_t timeline_start_pos;
83     WtvFile file[WTV_FILES];
84     int64_t serial;         /** chunk serial number */
85     int64_t last_chunk_pos; /** last chunk position */
86     int64_t frame_nb;
87
88     WtvChunkEntry index[MAX_NB_INDEX];
89     int nb_index;
90     int first_video_flag;
91     int64_t sync_pos;
92 } WtvContext;
93
94 typedef int WTVHeaderWriteFunc(AVIOContext *pb);
95
96 typedef struct {
97     const uint8_t *header;
98     int header_size;
99     WTVHeaderWriteFunc *write_header;
100 }WTVRootEntryTable;
101
102 static int write_pad(AVIOContext *pb, int size)
103 {
104     for (; size > 0; size--)
105         avio_w8(pb, 0);
106     return 0;
107 }
108
109 static void put_guid(AVIOContext *s, const ff_asf_guid *g)
110 {
111     assert(sizeof(*g) == 16);
112     avio_write(s, *g, sizeof(*g));
113  }
114
115 static const ff_asf_guid *get_codec_guid(enum CodecID id, const AVCodecGuid *av_guid)
116 {
117     int i;
118     for (i = 0; av_guid[i].id != CODEC_ID_NONE; i++) {
119         if (id == av_guid[i].id)
120             return &(av_guid[i].guid);
121     }
122     return NULL;
123 }
124
125 /**
126  * Write chunk header. If header chunk (0x80000000 set) then add to list of header chunks
127  */
128 static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id)
129 {
130     WtvContext *wctx = s->priv_data;
131     AVIOContext *pb = s->pb;
132
133     wctx->last_chunk_pos = avio_tell(pb) - wctx->timeline_start_pos;
134     put_guid(pb, guid);
135     avio_wl32(pb, 32 + length);
136     avio_wl32(pb, stream_id);
137     avio_wl64(pb, wctx->serial);
138
139     if ((stream_id & 0x80000000) && guid != &index_guid) {
140         WtvChunkEntry *t = wctx->index + wctx->nb_index;
141         av_assert0(wctx->nb_index < MAX_NB_INDEX);
142         t->pos       = wctx->last_chunk_pos;
143         t->serial    = wctx->serial;
144         t->guid      = guid;
145         t->stream_id = stream_id & 0x3FFFFFFF;
146         wctx->nb_index++;
147     }
148 }
149
150 static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id)
151 {
152     WtvContext *wctx = s->priv_data;
153     AVIOContext *pb = s->pb;
154
155     int64_t last_chunk_pos = wctx->last_chunk_pos;
156     write_chunk_header(s, guid, 0, stream_id); // length updated later
157     avio_wl64(pb, last_chunk_pos);
158 }
159
160 static void finish_chunk_noindex(AVFormatContext *s)
161 {
162     WtvContext *wctx = s->priv_data;
163     AVIOContext *pb = s->pb;
164
165     // update the chunk_len field and pad.
166     int64_t chunk_len = avio_tell(pb) - (wctx->last_chunk_pos + wctx->timeline_start_pos);
167     avio_seek(pb, -(chunk_len - 16), SEEK_CUR);
168     avio_wl32(pb, chunk_len);
169     avio_seek(pb, chunk_len - (16 + 4), SEEK_CUR);
170
171     write_pad(pb, WTV_PAD8(chunk_len) - chunk_len);
172     wctx->serial++;
173 }
174
175 static void write_index(AVFormatContext *s)
176 {
177     AVIOContext *pb = s->pb;
178     WtvContext *wctx = s->priv_data;
179     int i;
180
181     write_chunk_header2(s, &index_guid, 0x80000000);
182     avio_wl32(pb, 0);
183     avio_wl32(pb, 0);
184
185     for (i = 0; i < wctx->nb_index; i++) {
186         WtvChunkEntry *t = wctx->index + i;
187         put_guid(pb,  t->guid);
188         avio_wl64(pb, t->pos);
189         avio_wl32(pb, t->stream_id);
190         avio_wl32(pb, 0); // checksum?
191         avio_wl64(pb, t->serial);
192     }
193     wctx->nb_index = 0;   // reset index
194     finish_chunk_noindex(s);
195 }
196
197 static void finish_chunk(AVFormatContext *s)
198 {
199     WtvContext *wctx = s->priv_data;
200     finish_chunk_noindex(s);
201     if (wctx->nb_index == MAX_NB_INDEX)
202         write_index(s);
203 }
204
205 static int write_stream_codec_info(AVFormatContext *s, AVStream *st)
206 {
207     WtvContext *wctx = s->priv_data;
208     const ff_asf_guid *g, *media_type, *format_type;
209     AVIOContext *pb = s->pb;
210     int64_t  hdr_pos_start;
211     int hdr_size = 0;
212
213     if (st->codec->codec_type  == AVMEDIA_TYPE_VIDEO) {
214         g = get_codec_guid(st->codec->codec_id, ff_video_guids);
215         media_type = &ff_mediatype_video;
216         format_type = &ff_format_mpeg2_video;
217     } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
218         g = get_codec_guid(st->codec->codec_id, ff_codec_wav_guids);
219         media_type = &ff_mediatype_audio;
220         format_type = &ff_format_waveformatex;
221     }  else {
222         av_log(s, AV_LOG_ERROR, "unknown codec_type (0x%x)\n", st->codec->codec_type);
223         return -1;
224     }
225
226     if (g == NULL) {
227         av_log(s, AV_LOG_ERROR, "can't get video codec_id (0x%x) guid.\n", st->codec->codec_id);
228         return -1;
229     }
230
231     put_guid(pb, media_type); // mediatype
232     put_guid(pb, &ff_mediasubtype_cpfilters_processed); // subtype
233     write_pad(pb, 12);
234     put_guid(pb,&ff_format_cpfilters_processed); // format type
235     avio_wl32(pb, 0); // size
236
237     hdr_pos_start = avio_tell(pb);
238     if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
239         if (wctx->first_video_flag) {
240             write_pad(pb, 216); //The size is sensitive.
241             wctx->first_video_flag = 0;
242         } else {
243             write_pad(pb, 72); // aspect ratio
244             ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0);
245         }
246     } else {
247         ff_put_wav_header(pb, st->codec);
248     }
249     hdr_size = avio_tell(pb) - hdr_pos_start;
250
251     // seek back write hdr_size
252     avio_seek(pb, -(hdr_size + 4), SEEK_CUR);
253     avio_wl32(pb, hdr_size + 32);
254     avio_seek(pb, hdr_size, SEEK_CUR);
255     put_guid(pb, g);           // actual_subtype
256     put_guid(pb, format_type); // actual_formattype
257
258     return 0;
259 }
260
261 static int write_stream_codec(AVFormatContext *s, AVStream * st)
262 {
263     AVIOContext *pb = s->pb;
264     int ret;
265     write_chunk_header2(s, &stream1_guid, 0x80000000 | 0x01);
266
267     avio_wl32(pb,  0x01);
268     write_pad(pb, 4);
269     write_pad(pb, 4);
270
271     ret = write_stream_codec_info(s, st);
272     if (ret < 0) {
273         av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
274         return -1;
275     }
276
277     finish_chunk(s);
278     return 0;
279 }
280
281 static void write_sync(AVFormatContext *s)
282 {
283     AVIOContext *pb = s->pb;
284     WtvContext *wctx = s->priv_data;
285     int64_t last_chunk_pos = wctx->last_chunk_pos;
286     wctx->sync_pos = avio_tell(pb) - wctx->timeline_start_pos;;
287
288     write_chunk_header(s, &sync_guid, 0x18, 0);
289     write_pad(pb, 24);
290
291     finish_chunk(s);
292
293     wctx->last_chunk_pos = last_chunk_pos;
294 }
295
296 static void write_DSATTRIB_TRANSPORT_PROPERTIES_init(AVFormatContext *s, int stream_index)
297 {
298     AVIOContext *pb = s->pb;
299     write_chunk_header2(s, &ff_DSATTRIB_TRANSPORT_PROPERTIES, 0x80000000 | stream_index);
300     avio_wl64(pb, stream_index);
301     avio_wl64(pb, -1);
302     avio_wl64(pb, 0);
303     finish_chunk(s);
304 }
305
306 static int write_stream_data(AVFormatContext *s, AVStream *st, int flag)
307 {
308     AVIOContext *pb = s->pb;
309     int ret;
310
311     if (!flag) {
312         write_chunk_header2(s, &ff_stream_guid, 0x80000000 | (st->index + INDEX_BASE));
313         avio_wl32(pb, 0x00000001);
314         avio_wl32(pb, st->index + INDEX_BASE); //stream_id
315         avio_wl32(pb, 0x00000001);
316         write_pad(pb, 8);
317     } else {
318         write_chunk_header2(s, &ff_stream2_guid, 0x80000000 | (st->index + INDEX_BASE));
319         write_pad(pb, 4);
320     }
321
322     ret = write_stream_codec_info(s, st);
323     if (ret < 0) {
324         av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
325         return -1;
326     }
327     finish_chunk(s);
328
329     av_set_pts_info(st, 64, 1, 10000000);
330
331     return 0;
332 }
333
334 static int write_header(AVFormatContext *s)
335 {
336     AVIOContext *pb = s->pb;
337     WtvContext *wctx = s->priv_data;
338     int i, pad, ret;
339     AVStream *st;
340
341     put_guid(pb, &ff_wtv_guid);
342     put_guid(pb, &sub_wtv_guid);
343
344     avio_wl32(pb, 0x01);
345     avio_wl32(pb, 0x02);
346     avio_wl32(pb, 1 << WTV_SECTOR_BITS);
347     avio_wl32(pb, 1 << WTV_BIGSECTOR_BITS);
348
349     //write initial root fields
350     avio_wl32(pb, 0); // root_size, update later
351     write_pad(pb, 4);
352     avio_wl32(pb, 0); // root_sector, update it later.
353
354     write_pad(pb, 32);
355     avio_wl32(pb, 0); // file ends pointer, update it later.
356
357     pad = (1 << WTV_SECTOR_BITS) - avio_tell(pb);
358     write_pad(pb, pad);
359     wctx->timeline_start_pos = avio_tell(pb);
360
361     wctx->serial = 1;
362     wctx->last_chunk_pos = -1;
363     wctx->first_video_flag = 1;
364
365     for (i = 0; i < s->nb_streams; i++) {
366         st = s->streams[i];
367         ret = write_stream_codec(s, st);
368         if (ret < 0) {
369             av_log(s, AV_LOG_ERROR, "write stream codec failed codec_type(0x%x)\n", st->codec->codec_type);
370             return -1;
371         }
372         if (i + 1 < s->nb_streams) {
373             write_sync(s);
374         }
375     }
376
377     for (i = 0; i < s->nb_streams; i++) {
378         st = s->streams[i];
379         ret  = write_stream_data(s, st, 0);
380         if (ret < 0) {
381             av_log(s, AV_LOG_ERROR, "write stream data failed codec_type(0x%x)\n", st->codec->codec_type);
382             return -1;
383         }
384         ret = write_stream_data(s, st, 1);
385         if (ret < 0) {
386             av_log(s, AV_LOG_ERROR, "write stream2 data failed codec_type(0x%x)\n", st->codec->codec_type);
387             return -1;
388         }
389     }
390
391     for (i = 0; i < s->nb_streams; i++)
392         write_DSATTRIB_TRANSPORT_PROPERTIES_init(s, INDEX_BASE + i);
393
394     if (wctx->nb_index)
395         write_index(s);
396
397     return 0;
398 }
399
400 static void write_timestamp(AVFormatContext *s, AVPacket *pkt)
401 {
402     AVIOContext *pb = s->pb;
403     WtvContext  *wctx = s->priv_data;
404     AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
405     int flag = 0;
406     int64_t frame_number = 0;
407
408     if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
409         wctx->frame_nb++;
410         frame_number = wctx->frame_nb;
411         flag = pkt->flags & AV_PKT_FLAG_KEY ? 1 : 0;
412     }
413     write_chunk_header(s, &ff_timestamp_guid, 56, 0x40000000 | (INDEX_BASE + pkt->stream_index));
414     write_pad(pb, 8);
415     avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
416     avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
417
418     avio_wl64(pb, frame_number);
419     avio_wl64(pb, 0);
420     avio_wl64(pb, flag);
421     avio_wl64(pb, 0);
422 }
423
424 static int write_packet(AVFormatContext *s, AVPacket *pkt)
425 {
426     AVIOContext *pb = s->pb;
427     WtvContext  *wctx = s->priv_data;
428
429     // write timestamp chunk
430     write_timestamp(s, pkt);
431
432     write_chunk_header(s, &ff_data_guid, pkt->size, INDEX_BASE + pkt->stream_index);
433     avio_write(pb, pkt->data, pkt->size);
434     write_pad(pb, WTV_PAD8(pkt->size) - pkt->size);
435
436     wctx->serial++;
437     avio_flush(pb);
438     return 0;
439 }
440
441 static int write_table0_header_envents(AVIOContext *pb)
442 {
443     avio_wl32(pb, 0x10);
444     write_pad(pb, 84);
445     avio_wl64(pb, 0x32);
446     return 96;
447 }
448
449 static int write_table0_header_legacy_attrib(AVIOContext *pb)
450 {
451     int pad = 0;
452     avio_wl32(pb, 0xFFFFFFFF);
453     write_pad(pb, 12);
454     avio_write(pb, legacy_attrib, sizeof(legacy_attrib));
455     pad = WTV_PAD8(sizeof(legacy_attrib)) - sizeof(legacy_attrib);
456     write_pad(pb, pad);
457     write_pad(pb, 32);
458     return 48 + WTV_PAD8(sizeof(legacy_attrib));
459 }
460
461 static int write_table0_header_time(AVIOContext *pb)
462 {
463     avio_wl32(pb, 0x10);
464     write_pad(pb, 76);
465     avio_wl64(pb, 0x40);
466     return 88;
467 }
468
469 static const WTVRootEntryTable wtv_root_entry_table[] = {
470     { timeline_table_0_header_events,          sizeof(timeline_table_0_header_events),          write_table0_header_envents},
471     { ff_timeline_table_0_entries_Events_le16, sizeof(ff_timeline_table_0_entries_Events_le16), NULL},
472     { ff_timeline_le16,                        sizeof(ff_timeline_le16),                        NULL},
473     { table_0_header_legacy_attrib,            sizeof(table_0_header_legacy_attrib),            write_table0_header_legacy_attrib},
474     { ff_table_0_entries_legacy_attrib_le16,   sizeof(ff_table_0_entries_legacy_attrib_le16),   NULL},
475     { table_0_redirector_legacy_attrib,        sizeof(table_0_redirector_legacy_attrib),        NULL},
476     { table_0_header_time,                     sizeof(table_0_header_time),                     write_table0_header_time},
477     { ff_table_0_entries_time_le16,            sizeof(ff_table_0_entries_time_le16),            NULL},
478 };
479
480 static int write_root_table(AVFormatContext *s, int64_t sector_pos)
481 {
482     AVIOContext *pb = s->pb;
483     WtvContext  *wctx = s->priv_data;
484     int size, pad;
485     int i;
486
487     const WTVRootEntryTable *h = wtv_root_entry_table;
488     for (i = 0; i < sizeof(wtv_root_entry_table)/sizeof(WTVRootEntryTable); i++, h++) {
489         WtvFile *w = &wctx->file[i];
490         int filename_padding = WTV_PAD8(h->header_size) - h->header_size;
491         WTVHeaderWriteFunc *write = h->write_header;
492         int len = 0;
493         int64_t len_pos;
494
495         put_guid(pb, &ff_dir_entry_guid);
496         len_pos = avio_tell(pb);
497         avio_wl16(pb, 40 + h->header_size + filename_padding + 8); // maybe updated later
498         write_pad(pb, 6);
499         avio_wl64(pb, write ? 0 : w->length);// maybe update later
500         avio_wl32(pb, (h->header_size + filename_padding) >> 1);
501         write_pad(pb, 4);
502
503         avio_write(pb, h->header, h->header_size);
504         write_pad(pb, filename_padding);
505
506         if (write) {
507             len = write(pb);
508             // update length field
509             avio_seek(pb, len_pos, SEEK_SET);
510             avio_wl64(pb, 40 + h->header_size + filename_padding + len);
511             avio_wl64(pb, len |(1ULL<<62) | (1ULL<<60));
512             avio_seek(pb, 8 + h->header_size + filename_padding + len, SEEK_CUR);
513         } else {
514             avio_wl32(pb, w->first_sector);
515             avio_wl32(pb, w->depth);
516         }
517     }
518
519     // caculate root table size
520     size = avio_tell(pb) - sector_pos;
521     pad = WTV_SECTOR_SIZE- size;
522     write_pad(pb, pad);
523
524     return size;
525 }
526
527 static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift)
528 {
529     int i;
530     for (i = 0; i < nb_sectors; i++) {
531         avio_wl32(pb, start_sector + (i << shift));
532     }
533     // pad left sector pointer size
534     write_pad(pb, WTV_SECTOR_SIZE - (nb_sectors << 2));
535 }
536
537 static int write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth)
538 {
539     int64_t start_sector = start_pos >> WTV_SECTOR_BITS;
540     int shift = sector_bits - WTV_SECTOR_BITS;
541
542     int64_t fat = avio_tell(s->pb);
543     write_fat(s->pb, start_sector, nb_sectors, shift);
544
545     if (depth == 2) {
546         int64_t start_sector1 = fat >> WTV_SECTOR_BITS;
547         int nb_sectors1 = ((nb_sectors << 2) + WTV_SECTOR_SIZE - 1) / WTV_SECTOR_SIZE;
548         int64_t fat1 = avio_tell(s->pb);
549
550        write_fat(s->pb, start_sector1, nb_sectors1, 0);
551        return fat1;
552     }
553
554     return fat;
555 }
556
557 static void write_table_entries_events(AVFormatContext *s)
558 {
559     AVIOContext *pb = s->pb;
560     WtvContext *wctx = s->priv_data;
561
562     //FIXME: output frame_nb, position pairs.
563     //We only set the first sync_chunk position here.
564     avio_wl64(pb, 0x2);   avio_wl64(pb, wctx->sync_pos);
565 }
566
567 static void write_tag(AVIOContext *pb, const char *key, const char *value)
568 {
569     put_guid(pb, &ff_metadata_guid);
570     avio_wl32(pb, 1);
571     avio_wl32(pb, strlen(value)*2 + 2);
572     avio_put_str16le(pb, key);
573     avio_put_str16le(pb, value);
574 }
575
576 static void write_table_entries_attrib(AVFormatContext *s)
577 {
578     AVDictionaryEntry *tag = 0;
579
580     //FIXME: translate special tags (e.g. WM/Bitrate) to binary representation
581     ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
582     while((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
583         write_tag(s->pb, tag->key, tag->value);
584 }
585
586 static void write_table_redirector_legacy_attrib(AVFormatContext *s)
587 {
588     AVIOContext *pb = s->pb;
589     AVDictionaryEntry *tag = 0;
590     int64_t pos = 0;
591
592     //FIXME: translate special tags to binary representation
593     while((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
594         avio_wl64(pb, pos);
595         pos += 16 + 4 + 4 + strlen(tag->key)*2 + 2 + strlen(tag->value)*2 + 2;
596     }
597 }
598
599 /**
600  * Pad the remainder of a file
601  * Write out fat table
602  * @return <0 on error
603  */
604 static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos)
605 {
606     WtvContext *wctx = s->priv_data;
607     AVIOContext *pb = s->pb;
608     WtvFile *w = &wctx->file[index];
609     int64_t end_pos = avio_tell(pb);
610     int sector_bits, nb_sectors, pad;
611
612     av_assert0(index < WTV_FILES);
613
614     w->length = (end_pos - start_pos);
615
616     // determine optimal fat table depth, sector_bits, nb_sectors
617     if (w->length <= WTV_SECTOR_SIZE) {
618         w->depth = 0;
619         sector_bits = WTV_SECTOR_BITS;
620     } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
621         w->depth = 1;
622         sector_bits = WTV_SECTOR_BITS;
623     } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
624         w->depth = 1;
625         sector_bits = WTV_BIGSECTOR_BITS;
626     } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
627         w->depth = 2;
628         sector_bits = WTV_SECTOR_BITS;
629     } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
630         w->depth = 2;
631         sector_bits = WTV_BIGSECTOR_BITS;
632     } else {
633         av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (%"PRIi64" bytes)\n", w->length);
634         return -1;
635     }
636
637     // determine the nb_sectors
638     nb_sectors = (int)(w->length >> sector_bits);
639
640     // pad sector of timeline
641     pad = (1 << sector_bits) - (w->length % (1 << sector_bits));
642     if (pad) {
643         nb_sectors++;
644         write_pad(pb, pad);
645     }
646
647     //write fat table
648     if (w->depth > 0) {
649         w->first_sector = write_fat_sector(s, start_pos, nb_sectors, sector_bits, w->depth);
650     } else {
651         w->first_sector = start_pos;
652     }
653     w->first_sector >>= WTV_SECTOR_BITS;
654
655     w->length |= 1ULL<<60;
656     if (sector_bits == WTV_SECTOR_BITS)
657         w->length |= 1ULL<<63;
658
659     return 0;
660 }
661
662 static int write_trailer(AVFormatContext *s)
663 {
664     WtvContext *wctx = s->priv_data;
665     AVIOContext *pb = s->pb;
666     int root_size;
667     int64_t sector_pos;
668     int64_t start_pos, file_end_pos;
669
670     if (finish_file(s, WTV_TIMELINE, wctx->timeline_start_pos) < 0)
671         return -1;
672
673     start_pos = avio_tell(pb);
674     write_table_entries_events(s);
675     if (finish_file(s, WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS, start_pos) < 0)
676         return -1;
677
678     start_pos = avio_tell(pb);
679     write_table_entries_attrib(s);
680     if (finish_file(s, WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB, start_pos) < 0)
681         return -1;
682
683     start_pos = avio_tell(pb);
684     write_table_redirector_legacy_attrib(s);
685     if (finish_file(s, WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB, start_pos) < 0)
686         return -1;
687
688     start_pos = avio_tell(pb);
689     //FIXME: output timestamp, frame_nb pairs here.
690     if (finish_file(s, WTV_TABLE_0_ENTRIES_TIME, start_pos) < 0)
691         return -1;
692
693     // write root table
694     sector_pos = avio_tell(pb);
695     root_size = write_root_table(s, sector_pos);
696
697     file_end_pos = avio_tell(pb);
698     // update root value
699     avio_seek(pb, 0x30, SEEK_SET);
700     avio_wl32(pb, root_size);
701     avio_seek(pb, 4, SEEK_CUR);
702     avio_wl32(pb, sector_pos >> WTV_SECTOR_BITS);
703     avio_seek(pb, 0x5c, SEEK_SET);
704     avio_wl32(pb, file_end_pos >> WTV_SECTOR_BITS);
705
706     avio_flush(pb);
707     return 0;
708 }
709
710 AVOutputFormat ff_wtv_muxer = {
711     .name           = "wtv",
712     .long_name      = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
713     .extensions     = "wtv",
714     .priv_data_size = sizeof(WtvContext),
715     .audio_codec    = CODEC_ID_MP2,
716     .video_codec    = CODEC_ID_MPEG2VIDEO,
717     .write_header   = write_header,
718     .write_packet   = write_packet,
719     .write_trailer  = write_trailer,
720     .codec_tag      = (const AVCodecTag* const []){ ff_codec_bmp_tags,
721                                                     ff_codec_wav_tags, 0 },
722 };