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.
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.
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.
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
24 * Windows Television (WTV) demuxer
25 * @author Zhentan Feng <spyfeng at gmail dot com>
28 #include "libavutil/intreadwrite.h"
29 #include "libavutil/avassert.h"
31 #include "avio_internal.h"
36 #define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS)
37 #define INDEX_BASE 0x2
38 #define MAX_NB_INDEX 10
40 /* declare utf16le strings */
42 static const uint8_t timeline_table_0_header_events
[] =
43 {'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};
44 static const uint8_t table_0_header_legacy_attrib
[] =
45 {'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};
46 static const uint8_t table_0_redirector_legacy_attrib
[] =
47 {'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};
48 static const uint8_t table_0_header_time
[] =
49 {'t'_
'a'_
'b'_
'l'_
'e'_
'.'_
'0'_
'.'_
'h'_
'e'_
'a'_
'd'_
'e'_
'r'_
'.'_
't'_
'i'_
'm'_
'e', 0};
50 static const uint8_t legacy_attrib
[] =
51 {'l'_
'e'_
'g'_
'a'_
'c'_
'y'_
'_'_
'a'_
't'_
't'_
'r'_
'i'_
'b', 0};
54 static const ff_asf_guid sub_wtv_guid
=
55 {0x8C,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
58 WTV_TIMELINE_TABLE_0_HEADER_EVENTS
= 0,
59 WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS
,
61 WTV_TABLE_0_HEADER_LEGACY_ATTRIB
,
62 WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB
,
63 WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB
,
64 WTV_TABLE_0_HEADER_TIME
,
65 WTV_TABLE_0_ENTRIES_TIME
,
79 const ff_asf_guid
* guid
;
89 int64_t timeline_start_pos
;
90 WtvFile file
[WTV_FILES
];
91 int64_t serial
; /**< chunk serial number */
92 int64_t last_chunk_pos
; /**< last chunk position */
93 int64_t last_timestamp_pos
; /**< last timestamp chunk position */
94 int64_t first_index_pos
; /**< first index_chunk position */
96 WtvChunkEntry index
[MAX_NB_INDEX
];
100 WtvSyncEntry
*st_pairs
; /* (serial, timestamp) pairs */
102 WtvSyncEntry
*sp_pairs
; /* (serial, position) pairs */
112 static void add_serial_pair(WtvSyncEntry
** list
, int * count
, int64_t serial
, int64_t value
)
114 int new_count
= *count
+ 1;
115 WtvSyncEntry
*new_list
= av_realloc(*list
, new_count
* sizeof(WtvSyncEntry
));
118 new_list
[*count
] = (WtvSyncEntry
){serial
, value
};
123 typedef int WTVHeaderWriteFunc(AVIOContext
*pb
);
126 const uint8_t *header
;
128 WTVHeaderWriteFunc
*write_header
;
131 #define write_pad(pb, size) ffio_fill(pb, 0, size)
134 * Write chunk header. If header chunk (0x80000000 set) then add to list of header chunks
136 static void write_chunk_header(AVFormatContext
*s
, const ff_asf_guid
*guid
, int length
, int stream_id
)
138 WtvContext
*wctx
= s
->priv_data
;
139 AVIOContext
*pb
= s
->pb
;
141 wctx
->last_chunk_pos
= avio_tell(pb
) - wctx
->timeline_start_pos
;
142 ff_put_guid(pb
, guid
);
143 avio_wl32(pb
, 32 + length
);
144 avio_wl32(pb
, stream_id
);
145 avio_wl64(pb
, wctx
->serial
);
147 if ((stream_id
& 0x80000000) && guid
!= &ff_index_guid
) {
148 WtvChunkEntry
*t
= wctx
->index
+ wctx
->nb_index
;
149 av_assert0(wctx
->nb_index
< MAX_NB_INDEX
);
150 t
->pos
= wctx
->last_chunk_pos
;
151 t
->serial
= wctx
->serial
;
153 t
->stream_id
= stream_id
& 0x3FFFFFFF;
158 static void write_chunk_header2(AVFormatContext
*s
, const ff_asf_guid
*guid
, int stream_id
)
160 WtvContext
*wctx
= s
->priv_data
;
161 AVIOContext
*pb
= s
->pb
;
163 int64_t last_chunk_pos
= wctx
->last_chunk_pos
;
164 write_chunk_header(s
, guid
, 0, stream_id
); // length updated later
165 avio_wl64(pb
, last_chunk_pos
);
168 static void finish_chunk_noindex(AVFormatContext
*s
)
170 WtvContext
*wctx
= s
->priv_data
;
171 AVIOContext
*pb
= s
->pb
;
173 // update the chunk_len field and pad.
174 int64_t chunk_len
= avio_tell(pb
) - (wctx
->last_chunk_pos
+ wctx
->timeline_start_pos
);
175 avio_seek(pb
, -(chunk_len
- 16), SEEK_CUR
);
176 avio_wl32(pb
, chunk_len
);
177 avio_seek(pb
, chunk_len
- (16 + 4), SEEK_CUR
);
179 write_pad(pb
, WTV_PAD8(chunk_len
) - chunk_len
);
183 static void write_index(AVFormatContext
*s
)
185 AVIOContext
*pb
= s
->pb
;
186 WtvContext
*wctx
= s
->priv_data
;
189 write_chunk_header2(s
, &ff_index_guid
, 0x80000000);
193 for (i
= 0; i
< wctx
->nb_index
; i
++) {
194 WtvChunkEntry
*t
= wctx
->index
+ i
;
195 ff_put_guid(pb
, t
->guid
);
196 avio_wl64(pb
, t
->pos
);
197 avio_wl32(pb
, t
->stream_id
);
198 avio_wl32(pb
, 0); // checksum?
199 avio_wl64(pb
, t
->serial
);
201 wctx
->nb_index
= 0; // reset index
202 finish_chunk_noindex(s
);
204 if (!wctx
->first_index_pos
)
205 wctx
->first_index_pos
= wctx
->last_chunk_pos
;
208 static void finish_chunk(AVFormatContext
*s
)
210 WtvContext
*wctx
= s
->priv_data
;
211 finish_chunk_noindex(s
);
212 if (wctx
->nb_index
== MAX_NB_INDEX
)
216 static void put_videoinfoheader2(AVIOContext
*pb
, AVStream
*st
)
218 AVRational dar
= av_mul_q(st
->sample_aspect_ratio
, (AVRational
){st
->codec
->width
, st
->codec
->height
});
219 unsigned int num
, den
;
220 av_reduce(&num
, &den
, dar
.num
, dar
.den
, 0xFFFFFFFF);
222 /* VIDEOINFOHEADER2 */
225 avio_wl32(pb
, st
->codec
->width
);
226 avio_wl32(pb
, st
->codec
->height
);
233 avio_wl32(pb
, st
->codec
->bit_rate
);
235 avio_wl64(pb
, st
->avg_frame_rate
.num
&& st
->avg_frame_rate
.den
? INT64_C(10000000) / av_q2d(st
->avg_frame_rate
) : 0);
244 ff_put_bmp_header(pb
, st
->codec
, ff_codec_bmp_tags
, 0, 1);
246 if (st
->codec
->codec_id
== AV_CODEC_ID_MPEG2VIDEO
) {
247 int padding
= (st
->codec
->extradata_size
& 3) ? 4 - (st
->codec
->extradata_size
& 3) : 0;
250 avio_wl32(pb
, st
->codec
->extradata_size
+ padding
);
254 avio_write(pb
, st
->codec
->extradata
, st
->codec
->extradata_size
);
255 ffio_fill(pb
, 0, padding
);
259 static int write_stream_codec_info(AVFormatContext
*s
, AVStream
*st
)
261 const ff_asf_guid
*g
, *media_type
, *format_type
;
262 const AVCodecTag
*tags
;
263 AVIOContext
*pb
= s
->pb
;
264 int64_t hdr_pos_start
;
267 if (st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
268 g
= get_codec_guid(st
->codec
->codec_id
, ff_video_guids
);
269 media_type
= &ff_mediatype_video
;
270 format_type
= st
->codec
->codec_id
== AV_CODEC_ID_MPEG2VIDEO
? &ff_format_mpeg2_video
: &ff_format_videoinfo2
;
271 tags
= ff_codec_bmp_tags
;
272 } else if (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
273 g
= get_codec_guid(st
->codec
->codec_id
, ff_codec_wav_guids
);
274 media_type
= &ff_mediatype_audio
;
275 format_type
= &ff_format_waveformatex
;
276 tags
= ff_codec_wav_tags
;
278 av_log(s
, AV_LOG_ERROR
, "unknown codec_type (0x%x)\n", st
->codec
->codec_type
);
282 ff_put_guid(pb
, media_type
); // mediatype
283 ff_put_guid(pb
, &ff_mediasubtype_cpfilters_processed
); // subtype
285 ff_put_guid(pb
,&ff_format_cpfilters_processed
); // format type
286 avio_wl32(pb
, 0); // size
288 hdr_pos_start
= avio_tell(pb
);
289 if (st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
290 put_videoinfoheader2(pb
, st
);
292 if (ff_put_wav_header(pb
, st
->codec
, 0) < 0)
293 format_type
= &ff_format_none
;
295 hdr_size
= avio_tell(pb
) - hdr_pos_start
;
297 // seek back write hdr_size
298 avio_seek(pb
, -(hdr_size
+ 4), SEEK_CUR
);
299 avio_wl32(pb
, hdr_size
+ 32);
300 avio_seek(pb
, hdr_size
, SEEK_CUR
);
302 ff_put_guid(pb
, g
); // actual_subtype
304 int tag
= ff_codec_get_tag(tags
, st
->codec
->codec_id
);
306 av_log(s
, AV_LOG_ERROR
, "unsupported codec_id (0x%x)\n", st
->codec
->codec_id
);
310 avio_write(pb
, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID
}, 12);
312 ff_put_guid(pb
, format_type
); // actual_formattype
317 static int write_stream_codec(AVFormatContext
*s
, AVStream
* st
)
319 AVIOContext
*pb
= s
->pb
;
321 write_chunk_header2(s
, &ff_stream1_guid
, 0x80000000 | 0x01);
327 ret
= write_stream_codec_info(s
, st
);
329 av_log(s
, AV_LOG_ERROR
, "write stream codec info failed codec_type(0x%x)\n", st
->codec
->codec_type
);
337 static void write_sync(AVFormatContext
*s
)
339 AVIOContext
*pb
= s
->pb
;
340 WtvContext
*wctx
= s
->priv_data
;
341 int64_t last_chunk_pos
= wctx
->last_chunk_pos
;
343 write_chunk_header(s
, &ff_sync_guid
, 0x18, 0);
344 avio_wl64(pb
, wctx
->first_index_pos
);
345 avio_wl64(pb
, wctx
->last_timestamp_pos
);
349 add_serial_pair(&wctx
->sp_pairs
, &wctx
->nb_sp_pairs
, wctx
->serial
, wctx
->last_chunk_pos
);
351 wctx
->last_chunk_pos
= last_chunk_pos
;
354 static int write_stream_data(AVFormatContext
*s
, AVStream
*st
)
356 AVIOContext
*pb
= s
->pb
;
359 write_chunk_header2(s
, &ff_SBE2_STREAM_DESC_EVENT
, 0x80000000 | (st
->index
+ INDEX_BASE
));
360 avio_wl32(pb
, 0x00000001);
361 avio_wl32(pb
, st
->index
+ INDEX_BASE
); //stream_id
362 avio_wl32(pb
, 0x00000001);
365 ret
= write_stream_codec_info(s
, st
);
367 av_log(s
, AV_LOG_ERROR
, "write stream codec info failed codec_type(0x%x)\n", st
->codec
->codec_type
);
372 avpriv_set_pts_info(st
, 64, 1, 10000000);
377 static int write_header(AVFormatContext
*s
)
379 AVIOContext
*pb
= s
->pb
;
380 WtvContext
*wctx
= s
->priv_data
;
384 wctx
->last_chunk_pos
= -1;
385 wctx
->last_timestamp_pos
= -1;
387 ff_put_guid(pb
, &ff_wtv_guid
);
388 ff_put_guid(pb
, &sub_wtv_guid
);
392 avio_wl32(pb
, 1 << WTV_SECTOR_BITS
);
393 avio_wl32(pb
, 1 << WTV_BIGSECTOR_BITS
);
395 //write initial root fields
396 avio_wl32(pb
, 0); // root_size, update later
398 avio_wl32(pb
, 0); // root_sector, update it later.
401 avio_wl32(pb
, 0); // file ends pointer, update it later.
403 pad
= (1 << WTV_SECTOR_BITS
) - avio_tell(pb
);
406 wctx
->timeline_start_pos
= avio_tell(pb
);
409 wctx
->last_chunk_pos
= -1;
410 wctx
->first_video_flag
= 1;
412 for (i
= 0; i
< s
->nb_streams
; i
++) {
414 if (st
->codec
->codec_id
== AV_CODEC_ID_MJPEG
)
416 ret
= write_stream_codec(s
, st
);
418 av_log(s
, AV_LOG_ERROR
, "write stream codec failed codec_type(0x%x)\n", st
->codec
->codec_type
);
425 for (i
= 0; i
< s
->nb_streams
; i
++) {
427 if (st
->codec
->codec_id
== AV_CODEC_ID_MJPEG
)
429 ret
= write_stream_data(s
, st
);
431 av_log(s
, AV_LOG_ERROR
, "write stream data failed codec_type(0x%x)\n", st
->codec
->codec_type
);
442 static void write_timestamp(AVFormatContext
*s
, AVPacket
*pkt
)
444 AVIOContext
*pb
= s
->pb
;
445 WtvContext
*wctx
= s
->priv_data
;
446 AVCodecContext
*enc
= s
->streams
[pkt
->stream_index
]->codec
;
448 write_chunk_header(s
, &ff_timestamp_guid
, 56, 0x40000000 | (INDEX_BASE
+ pkt
->stream_index
));
450 avio_wl64(pb
, pkt
->pts
== AV_NOPTS_VALUE
? -1 : pkt
->pts
);
451 avio_wl64(pb
, pkt
->pts
== AV_NOPTS_VALUE
? -1 : pkt
->pts
);
452 avio_wl64(pb
, pkt
->pts
== AV_NOPTS_VALUE
? -1 : pkt
->pts
);
454 avio_wl64(pb
, enc
->codec_type
== AVMEDIA_TYPE_VIDEO
&& (pkt
->flags
& AV_PKT_FLAG_KEY
) ? 1 : 0);
457 wctx
->last_timestamp_pos
= wctx
->last_chunk_pos
;
460 static int write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
462 AVIOContext
*pb
= s
->pb
;
463 WtvContext
*wctx
= s
->priv_data
;
464 AVStream
*st
= s
->streams
[pkt
->stream_index
];
466 if (st
->codec
->codec_id
== AV_CODEC_ID_MJPEG
&& !wctx
->thumbnail
.size
) {
467 av_copy_packet(&wctx
->thumbnail
, pkt
);
469 } else if (st
->codec
->codec_id
== AV_CODEC_ID_H264
) {
470 int ret
= ff_check_h264_startcode(s
, st
, pkt
);
475 /* emit sync chunk and 'timeline.table.0.entries.Event' record every 50 frames */
476 if (wctx
->serial
- (wctx
->nb_sp_pairs
? wctx
->sp_pairs
[wctx
->nb_sp_pairs
- 1].serial
: 0) >= 50)
479 /* emit 'table.0.entries.time' record every 500ms */
480 if (pkt
->pts
!= AV_NOPTS_VALUE
&& pkt
->pts
- (wctx
->nb_st_pairs
? wctx
->st_pairs
[wctx
->nb_st_pairs
- 1].value
: 0) >= 5000000)
481 add_serial_pair(&wctx
->st_pairs
, &wctx
->nb_st_pairs
, wctx
->serial
, pkt
->pts
);
483 if (pkt
->pts
!= AV_NOPTS_VALUE
&& pkt
->pts
> wctx
->last_pts
) {
484 wctx
->last_pts
= pkt
->pts
;
485 wctx
->last_serial
= wctx
->serial
;
488 // write timestamp chunk
489 write_timestamp(s
, pkt
);
491 write_chunk_header(s
, &ff_data_guid
, pkt
->size
, INDEX_BASE
+ pkt
->stream_index
);
492 avio_write(pb
, pkt
->data
, pkt
->size
);
493 write_pad(pb
, WTV_PAD8(pkt
->size
) - pkt
->size
);
499 static int write_table0_header_events(AVIOContext
*pb
)
507 static int write_table0_header_legacy_attrib(AVIOContext
*pb
)
510 avio_wl32(pb
, 0xFFFFFFFF);
512 avio_write(pb
, legacy_attrib
, sizeof(legacy_attrib
));
513 pad
= WTV_PAD8(sizeof(legacy_attrib
)) - sizeof(legacy_attrib
);
516 return 48 + WTV_PAD8(sizeof(legacy_attrib
));
519 static int write_table0_header_time(AVIOContext
*pb
)
527 static const WTVRootEntryTable wtv_root_entry_table
[] = {
528 { timeline_table_0_header_events
, sizeof(timeline_table_0_header_events
), write_table0_header_events
},
529 { ff_timeline_table_0_entries_Events_le16
, sizeof(ff_timeline_table_0_entries_Events_le16
), NULL
},
530 { ff_timeline_le16
, sizeof(ff_timeline_le16
), NULL
},
531 { table_0_header_legacy_attrib
, sizeof(table_0_header_legacy_attrib
), write_table0_header_legacy_attrib
},
532 { ff_table_0_entries_legacy_attrib_le16
, sizeof(ff_table_0_entries_legacy_attrib_le16
), NULL
},
533 { table_0_redirector_legacy_attrib
, sizeof(table_0_redirector_legacy_attrib
), NULL
},
534 { table_0_header_time
, sizeof(table_0_header_time
), write_table0_header_time
},
535 { ff_table_0_entries_time_le16
, sizeof(ff_table_0_entries_time_le16
), NULL
},
538 static int write_root_table(AVFormatContext
*s
, int64_t sector_pos
)
540 AVIOContext
*pb
= s
->pb
;
541 WtvContext
*wctx
= s
->priv_data
;
545 const WTVRootEntryTable
*h
= wtv_root_entry_table
;
546 for (i
= 0; i
< sizeof(wtv_root_entry_table
)/sizeof(WTVRootEntryTable
); i
++, h
++) {
547 WtvFile
*w
= &wctx
->file
[i
];
548 int filename_padding
= WTV_PAD8(h
->header_size
) - h
->header_size
;
549 WTVHeaderWriteFunc
*write
= h
->write_header
;
553 ff_put_guid(pb
, &ff_dir_entry_guid
);
554 len_pos
= avio_tell(pb
);
555 avio_wl16(pb
, 40 + h
->header_size
+ filename_padding
+ 8); // maybe updated later
557 avio_wl64(pb
, write
? 0 : w
->length
);// maybe update later
558 avio_wl32(pb
, (h
->header_size
+ filename_padding
) >> 1);
561 avio_write(pb
, h
->header
, h
->header_size
);
562 write_pad(pb
, filename_padding
);
566 // update length field
567 avio_seek(pb
, len_pos
, SEEK_SET
);
568 avio_wl64(pb
, 40 + h
->header_size
+ filename_padding
+ len
);
569 avio_wl64(pb
, len
|(1ULL<<62) | (1ULL<<60));
570 avio_seek(pb
, 8 + h
->header_size
+ filename_padding
+ len
, SEEK_CUR
);
572 avio_wl32(pb
, w
->first_sector
);
573 avio_wl32(pb
, w
->depth
);
577 // caculate root table size
578 size
= avio_tell(pb
) - sector_pos
;
579 pad
= WTV_SECTOR_SIZE
- size
;
585 static void write_fat(AVIOContext
*pb
, int start_sector
, int nb_sectors
, int shift
)
588 for (i
= 0; i
< nb_sectors
; i
++) {
589 avio_wl32(pb
, start_sector
+ (i
<< shift
));
591 // pad left sector pointer size
592 write_pad(pb
, WTV_SECTOR_SIZE
- ((nb_sectors
<< 2) % WTV_SECTOR_SIZE
));
595 static int64_t write_fat_sector(AVFormatContext
*s
, int64_t start_pos
, int nb_sectors
, int sector_bits
, int depth
)
597 int64_t start_sector
= start_pos
>> WTV_SECTOR_BITS
;
598 int shift
= sector_bits
- WTV_SECTOR_BITS
;
600 int64_t fat
= avio_tell(s
->pb
);
601 write_fat(s
->pb
, start_sector
, nb_sectors
, shift
);
604 int64_t start_sector1
= fat
>> WTV_SECTOR_BITS
;
605 int nb_sectors1
= ((nb_sectors
<< 2) + WTV_SECTOR_SIZE
- 1) / WTV_SECTOR_SIZE
;
606 int64_t fat1
= avio_tell(s
->pb
);
608 write_fat(s
->pb
, start_sector1
, nb_sectors1
, 0);
615 static void write_table_entries_events(AVFormatContext
*s
)
617 AVIOContext
*pb
= s
->pb
;
618 WtvContext
*wctx
= s
->priv_data
;
620 for (i
= 0; i
< wctx
->nb_sp_pairs
; i
++) {
621 avio_wl64(pb
, wctx
->sp_pairs
[i
].serial
);
622 avio_wl64(pb
, wctx
->sp_pairs
[i
].value
);
626 static void write_table_entries_time(AVFormatContext
*s
)
628 AVIOContext
*pb
= s
->pb
;
629 WtvContext
*wctx
= s
->priv_data
;
631 for (i
= 0; i
< wctx
->nb_st_pairs
; i
++) {
632 avio_wl64(pb
, wctx
->st_pairs
[i
].value
);
633 avio_wl64(pb
, wctx
->st_pairs
[i
].serial
);
635 avio_wl64(pb
, wctx
->last_pts
);
636 avio_wl64(pb
, wctx
->last_serial
);
639 static void write_metadata_header(AVIOContext
*pb
, int type
, const char *key
, int value_size
)
641 ff_put_guid(pb
, &ff_metadata_guid
);
643 avio_wl32(pb
, value_size
);
644 avio_put_str16le(pb
, key
);
647 static int metadata_header_size(const char *key
)
649 return 16 + 4 + 4 + strlen(key
)*2 + 2;
652 static void write_tag_int32(AVIOContext
*pb
, const char *key
, int value
)
654 write_metadata_header(pb
, 0, key
, 4);
655 avio_wl32(pb
, value
);
658 static void write_tag(AVIOContext
*pb
, const char *key
, const char *value
)
660 write_metadata_header(pb
, 1, key
, strlen(value
)*2 + 2);
661 avio_put_str16le(pb
, value
);
664 static int attachment_value_size(const AVPacket
*pkt
, const AVDictionaryEntry
*e
)
666 return strlen("image/jpeg")*2 + 2 + 1 + (e
? strlen(e
->value
)*2 : 0) + 2 + 4 + pkt
->size
;
669 static void write_table_entries_attrib(AVFormatContext
*s
)
671 WtvContext
*wctx
= s
->priv_data
;
672 AVIOContext
*pb
= s
->pb
;
673 AVDictionaryEntry
*tag
= 0;
675 //FIXME: translate special tags (e.g. WM/Bitrate) to binary representation
676 ff_metadata_conv(&s
->metadata
, ff_asf_metadata_conv
, NULL
);
677 while ((tag
= av_dict_get(s
->metadata
, "", tag
, AV_DICT_IGNORE_SUFFIX
)))
678 write_tag(pb
, tag
->key
, tag
->value
);
680 if (wctx
->thumbnail
.size
) {
681 AVStream
*st
= s
->streams
[wctx
->thumbnail
.stream_index
];
682 tag
= av_dict_get(st
->metadata
, "title", NULL
, 0);
683 write_metadata_header(pb
, 2, "WM/Picture", attachment_value_size(&wctx
->thumbnail
, tag
));
685 avio_put_str16le(pb
, "image/jpeg");
687 avio_put_str16le(pb
, tag
? tag
->value
: "");
689 avio_wl32(pb
, wctx
->thumbnail
.size
);
690 avio_write(pb
, wctx
->thumbnail
.data
, wctx
->thumbnail
.size
);
692 write_tag_int32(pb
, "WM/MediaThumbType", 2);
696 static void write_table_redirector_legacy_attrib(AVFormatContext
*s
)
698 WtvContext
*wctx
= s
->priv_data
;
699 AVIOContext
*pb
= s
->pb
;
700 AVDictionaryEntry
*tag
= 0;
703 //FIXME: translate special tags to binary representation
704 while ((tag
= av_dict_get(s
->metadata
, "", tag
, AV_DICT_IGNORE_SUFFIX
))) {
706 pos
+= metadata_header_size(tag
->key
) + strlen(tag
->value
)*2 + 2;
709 if (wctx
->thumbnail
.size
) {
710 AVStream
*st
= s
->streams
[wctx
->thumbnail
.stream_index
];
712 pos
+= metadata_header_size("WM/Picture") + attachment_value_size(&wctx
->thumbnail
, av_dict_get(st
->metadata
, "title", NULL
, 0));
715 pos
+= metadata_header_size("WM/MediaThumbType") + 4;
720 * Pad the remainder of a file
721 * Write out fat table
722 * @return <0 on error
724 static int finish_file(AVFormatContext
*s
, enum WtvFileIndex index
, int64_t start_pos
)
726 WtvContext
*wctx
= s
->priv_data
;
727 AVIOContext
*pb
= s
->pb
;
728 WtvFile
*w
= &wctx
->file
[index
];
729 int64_t end_pos
= avio_tell(pb
);
730 int sector_bits
, nb_sectors
, pad
;
732 av_assert0(index
< WTV_FILES
);
734 w
->length
= (end_pos
- start_pos
);
736 // determine optimal fat table depth, sector_bits, nb_sectors
737 if (w
->length
<= WTV_SECTOR_SIZE
) {
739 sector_bits
= WTV_SECTOR_BITS
;
740 } else if (w
->length
<= (WTV_SECTOR_SIZE
/ 4) * WTV_SECTOR_SIZE
) {
742 sector_bits
= WTV_SECTOR_BITS
;
743 } else if (w
->length
<= (WTV_SECTOR_SIZE
/ 4) * WTV_BIGSECTOR_SIZE
) {
745 sector_bits
= WTV_BIGSECTOR_BITS
;
746 } else if (w
->length
<= (int64_t)(WTV_SECTOR_SIZE
/ 4) * (WTV_SECTOR_SIZE
/ 4) * WTV_SECTOR_SIZE
) {
748 sector_bits
= WTV_SECTOR_BITS
;
749 } else if (w
->length
<= (int64_t)(WTV_SECTOR_SIZE
/ 4) * (WTV_SECTOR_SIZE
/ 4) * WTV_BIGSECTOR_SIZE
) {
751 sector_bits
= WTV_BIGSECTOR_BITS
;
753 av_log(s
, AV_LOG_ERROR
, "unsupported file allocation table depth (%"PRIi64
" bytes)\n", w
->length
);
757 // determine the nb_sectors
758 nb_sectors
= (int)(w
->length
>> sector_bits
);
760 // pad sector of timeline
761 pad
= (1 << sector_bits
) - (w
->length
% (1 << sector_bits
));
769 w
->first_sector
= write_fat_sector(s
, start_pos
, nb_sectors
, sector_bits
, w
->depth
) >> WTV_SECTOR_BITS
;
771 w
->first_sector
= start_pos
>> WTV_SECTOR_BITS
;
774 w
->length
|= 1ULL<<60;
775 if (sector_bits
== WTV_SECTOR_BITS
)
776 w
->length
|= 1ULL<<63;
781 static int write_trailer(AVFormatContext
*s
)
783 WtvContext
*wctx
= s
->priv_data
;
784 AVIOContext
*pb
= s
->pb
;
787 int64_t start_pos
, file_end_pos
;
789 if (finish_file(s
, WTV_TIMELINE
, wctx
->timeline_start_pos
) < 0)
792 start_pos
= avio_tell(pb
);
793 write_table_entries_events(s
);
794 if (finish_file(s
, WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS
, start_pos
) < 0)
797 start_pos
= avio_tell(pb
);
798 write_table_entries_attrib(s
);
799 if (finish_file(s
, WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB
, start_pos
) < 0)
802 start_pos
= avio_tell(pb
);
803 write_table_redirector_legacy_attrib(s
);
804 if (finish_file(s
, WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB
, start_pos
) < 0)
807 start_pos
= avio_tell(pb
);
808 write_table_entries_time(s
);
809 if (finish_file(s
, WTV_TABLE_0_ENTRIES_TIME
, start_pos
) < 0)
813 sector_pos
= avio_tell(pb
);
814 root_size
= write_root_table(s
, sector_pos
);
816 file_end_pos
= avio_tell(pb
);
818 avio_seek(pb
, 0x30, SEEK_SET
);
819 avio_wl32(pb
, root_size
);
820 avio_seek(pb
, 4, SEEK_CUR
);
821 avio_wl32(pb
, sector_pos
>> WTV_SECTOR_BITS
);
822 avio_seek(pb
, 0x5c, SEEK_SET
);
823 avio_wl32(pb
, file_end_pos
>> WTV_SECTOR_BITS
);
827 av_free(wctx
->sp_pairs
);
828 av_free(wctx
->st_pairs
);
829 av_free_packet(&wctx
->thumbnail
);
833 AVOutputFormat ff_wtv_muxer
= {
835 .long_name
= NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
837 .priv_data_size
= sizeof(WtvContext
),
838 .audio_codec
= AV_CODEC_ID_AC3
,
839 .video_codec
= AV_CODEC_ID_MPEG2VIDEO
,
840 .write_header
= write_header
,
841 .write_packet
= write_packet
,
842 .write_trailer
= write_trailer
,
843 .codec_tag
= (const AVCodecTag
* const []){ ff_codec_bmp_tags
,
844 ff_codec_wav_tags
, 0 },