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 /**
23 * @file
24 * Windows Television (WTV) demuxer
25 * @author Zhentan Feng <spyfeng at gmail dot com>
26 */
27
35
36 #define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS)
37 #define INDEX_BASE 0x2
38 #define MAX_NB_INDEX 10
39
40 /* declare utf16le strings */
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};
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};
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};
49 {
't'_ 'a'_ 'b'_ 'l'_ 'e'_ '.'_ '0'_ '.'_ 'h'_ 'e'_ 'a'_ 'd'_ 'e'_ 'r'_ '.'_ 't'_ 'i'_ 'm'_ 'e', 0};
51 {
'l'_ 'e'_ 'g'_ 'a'_ 'c'_ 'y'_ '_'_ 'a'_ 't'_ 't'_ 'r'_ 'i'_ 'b', 0};
52 #undef _
53
55 {0x8C,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
56
67 };
68
69 typedef struct {
75
82
87
88 typedef struct {
91 int64_t
serial;
/**< chunk serial number */
95
99
104
107
110
111
113 {
114 int new_count = *count + 1;
116 if (!new_list)
117 return;
119 *list = new_list;
120 *count = new_count;
121 }
122
124
130
131 #define write_pad(pb, size) ffio_fill(pb, 0, size)
132
133 /**
134 * Write chunk header. If header chunk (0x80000000 set) then add to list of header chunks
135 */
137 {
140
146
155 }
156 }
157
159 {
162
166 }
167
169 {
172
173 // update the chunk_len field and pad.
175 avio_seek(pb, -(chunk_len - 16), SEEK_CUR);
177 avio_seek(pb, chunk_len - (16 + 4), SEEK_CUR);
178
181 }
182
184 {
187 int i;
188
192
193 for (i = 0; i < wctx->
nb_index; i++) {
200 }
203
206 }
207
209 {
214 }
215
217 {
219 unsigned int num, den;
220 av_reduce(&num, &den, dar.num, dar.den, 0xFFFFFFFF);
221
222 /* VIDEOINFOHEADER2 */
227
232
235 avio_wl64(pb, st->avg_frame_rate.num && st->avg_frame_rate.den ? INT64_C(10000000) /
av_q2d(st->avg_frame_rate) : 0);
238
243
245
247 int padding = (st->codec->extradata_size & 3) ? 4 - (st->codec->extradata_size & 3) : 0;
248 /* MPEG2VIDEOINFO */
250 avio_wl32(pb, st->codec->extradata_size + padding);
254 avio_write(pb, st->codec->extradata, st->codec->extradata_size);
256 }
257 }
258
260 {
264 int64_t hdr_pos_start;
265 int hdr_size = 0;
266
277 } else {
279 return -1;
280 }
281
287
291 } else {
294 }
295 hdr_size =
avio_tell(pb) - hdr_pos_start;
296
297 // seek back write hdr_size
298 avio_seek(pb, -(hdr_size + 4), SEEK_CUR);
301 if (g) {
303 } else {
305 if (!tag) {
307 return -1;
308 }
311 }
313
314 return 0;
315 }
316
318 {
320 int ret;
322
326
328 if (ret < 0) {
330 return -1;
331 }
332
334 return 0;
335 }
336
338 {
342
347
350
352 }
353
355 {
357 int ret;
358
364
366 if (ret < 0) {
368 return -1;
369 }
371
373
374 return 0;
375 }
376
378 {
381 int i, pad, ret;
383
386
389
394
395 //write initial root fields
396 avio_wl32(pb, 0);
// root_size, update later
398 avio_wl32(pb, 0);
// root_sector, update it later.
399
401 avio_wl32(pb, 0);
// file ends pointer, update it later.
402
405
407
411
415 continue;
417 if (ret < 0) {
419 return -1;
420 }
421 if (!i)
423 }
424
428 continue;
430 if (ret < 0) {
432 return -1;
433 }
434 }
435
438
439 return 0;
440 }
441
443 {
447
456
458 }
459
461 {
465
468 return 0;
471 if (ret < 0)
472 return ret;
473 }
474
475 /* emit sync chunk and 'timeline.table.0.entries.Event' record every 50 frames */
478
479 /* emit 'table.0.entries.time' record every 500ms */
482
486 }
487
488 // write timestamp chunk
490
494
496 return 0;
497 }
498
500 {
504 return 96;
505 }
506
508 {
509 int pad = 0;
517 }
518
520 {
524 return 88;
525 }
526
536 };
537
539 {
543 int i;
544
551 int64_t len_pos;
552
560
563
564 if (write) {
565 len = write(pb);
566 // update length field
569 avio_wl64(pb, len |(1ULL<<62) | (1ULL<<60));
571 } else {
574 }
575 }
576
577 // caculate root table size
581
583 }
584
586 {
587 int i;
588 for (i = 0; i < nb_sectors; i++) {
589 avio_wl32(pb, start_sector + (i << shift));
590 }
591 // pad left sector pointer size
593 }
594
596 {
599
602
603 if (depth == 2) {
607
609 return fat1;
610 }
611
612 return fat;
613 }
614
616 {
619 int i;
623 }
624 }
625
627 {
630 int i;
634 }
637 }
638
640 {
645 }
646
648 {
649 return 16 + 4 + 4 + strlen(key)*2 + 2;
650 }
651
653 {
656 }
657
659 {
662 }
663
665 {
666 return strlen(
"image/jpeg")*2 + 2 + 1 + (e ? strlen(e->
value)*2 : 0) + 2 + 4 + pkt->
size;
667 }
668
670 {
674
675 //FIXME: translate special tags (e.g. WM/Bitrate) to binary representation
679
684
688
691
693 }
694 }
695
697 {
701 int64_t pos = 0;
702
703 //FIXME: translate special tags to binary representation
707 }
708
713
716 }
717 }
718
719 /**
720 * Pad the remainder of a file
721 * Write out fat table
722 * @return <0 on error
723 */
725 {
730 int sector_bits, nb_sectors, pad;
731
733
734 w->
length = (end_pos - start_pos);
735
736 // determine optimal fat table depth, sector_bits, nb_sectors
752 } else {
754 return -1;
755 }
756
757 // determine the nb_sectors
758 nb_sectors = (int)(w->
length >> sector_bits);
759
760 // pad sector of timeline
761 pad = (1 << sector_bits) - (w->
length % (1 << sector_bits));
762 if (pad) {
763 nb_sectors++;
765 }
766
767 //write fat table
770 } else {
772 }
773
777
778 return 0;
779 }
780
782 {
785 int root_size;
786 int64_t sector_pos;
787 int64_t start_pos, file_end_pos;
788
790 return -1;
791
795 return -1;
796
800 return -1;
801
805 return -1;
806
810 return -1;
811
812 // write root table
815
817 // update root value
824
826
830 return 0;
831 }
832
836 .extensions = "wtv",
845 };
const uint8_t ff_table_0_entries_time_le16[40]
const ff_asf_guid ff_metadata_guid
static void write_table_entries_time(AVFormatContext *s)
const ff_asf_guid ff_SBE2_STREAM_DESC_EVENT
void avio_wl16(AVIOContext *s, unsigned int val)
static int shift(int a, int b)
#define WTV_BIGSECTOR_BITS
static int attachment_value_size(const AVPacket *pkt, const AVDictionaryEntry *e)
void ff_put_guid(AVIOContext *s, const ff_asf_guid *g)
static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift)
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
int index
stream index in AVFormatContext
const ff_asf_guid * ff_get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid)
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
static int64_t write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth)
const ff_asf_guid ff_mediatype_video
static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id)
int64_t last_timestamp_pos
last timestamp chunk position
static int write_table0_header_time(AVIOContext *pb)
const ff_asf_guid ff_format_waveformatex
const AVCodecGuid ff_codec_wav_guids[]
static int write_root_table(AVFormatContext *s, int64_t sector_pos)
#define av_assert0(cond)
assert() equivalent, that is always enabled.
static void write_table_redirector_legacy_attrib(AVFormatContext *s)
const ff_asf_guid ff_data_guid
void avio_wl32(AVIOContext *s, unsigned int val)
#define FF_MEDIASUBTYPE_BASE_GUID
static void add_serial_pair(WtvSyncEntry **list, int *count, int64_t serial, int64_t value)
static void put_videoinfoheader2(AVIOContext *pb, AVStream *st)
static const uint8_t table_0_redirector_legacy_attrib[]
const ff_asf_guid ff_mediatype_audio
AVStream ** streams
A list of all streams in the file.
const ff_asf_guid ff_mediasubtype_cpfilters_processed
static double av_q2d(AVRational a)
Convert rational to double.
static const ff_asf_guid sub_wtv_guid
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
static int write_stream_codec(AVFormatContext *s, AVStream *st)
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
static void finish_chunk_noindex(AVFormatContext *s)
static int metadata_header_size(const char *key)
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
const ff_asf_guid ff_sync_guid
WTVHeaderWriteFunc * write_header
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
void avio_wl64(AVIOContext *s, uint64_t val)
WtvChunkEntry index[MAX_NB_INDEX]
const uint8_t ff_table_0_entries_legacy_attrib_le16[58]
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
AVDictionary * metadata
Metadata that applies to the whole file.
static void write_sync(AVFormatContext *s)
int ff_check_h264_startcode(AVFormatContext *s, const AVStream *st, const AVPacket *pkt)
Check presence of H264 startcode.
static const uint8_t legacy_attrib[]
int WTVHeaderWriteFunc(AVIOContext *pb)
static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id)
Write chunk header.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
int64_t timeline_start_pos
simple assert() macros that are a bit more flexible than ISO C assert().
static void write_index(AVFormatContext *s)
const AVCodecTag ff_codec_wav_tags[]
const uint8_t ff_timeline_table_0_entries_Events_le16[62]
int flags
A combination of AV_PKT_FLAG values.
#define write_pad(pb, size)
AVCodecContext * codec
Codec context associated with this stream.
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
const ff_asf_guid ff_format_cpfilters_processed
static const uint8_t table_0_header_time[]
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
static const WTVRootEntryTable wtv_root_entry_table[]
int void avio_flush(AVIOContext *s)
Force flushing of buffered data.
void ffio_fill(AVIOContext *s, int b, int count)
const AVCodecTag ff_codec_bmp_tags[]
int width
picture width / height.
static int write_table0_header_legacy_attrib(AVIOContext *pb)
GLsizei GLboolean const GLfloat * value
const uint8_t ff_timeline_le16[16]
const ff_asf_guid ff_timestamp_guid
static void write_table_entries_attrib(AVFormatContext *s)
const ff_asf_guid ff_format_mpeg2_video
static const uint8_t timeline_table_0_header_events[]
preferred ID for MPEG-1/2 video decoding
static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos)
Pad the remainder of a file Write out fat table.
static void write_timestamp(AVFormatContext *s, AVPacket *pkt)
enum AVMediaType codec_type
AVIOContext * pb
I/O context.
static int write_stream_codec_info(AVFormatContext *s, AVStream *st)
void avio_w8(AVIOContext *s, int b)
main external API structure.
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
int av_copy_packet(AVPacket *dst, const AVPacket *src)
Copy packet, including contents.
static int write_trailer(AVFormatContext *s)
const ff_asf_guid ff_index_guid
rational number numerator/denominator
static void finish_chunk(AVFormatContext *s)
void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf, int ignore_extradata)
const AVCodecGuid ff_video_guids[]
int avio_put_str16le(AVIOContext *s, const char *str)
Convert an UTF-8 string to UTF-16LE and write it.
const AVMetadataConv ff_asf_metadata_conv[]
static int write_table0_header_events(AVIOContext *pb)
AVOutputFormat ff_wtv_muxer
static int write_header(AVFormatContext *s)
static void write_tag(AVIOContext *pb, const char *key, const char *value)
const ff_asf_guid ff_dir_entry_guid
static int write_stream_data(AVFormatContext *s, AVStream *st)
#define WTV_BIGSECTOR_SIZE
int64_t serial
chunk serial number
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
static const uint8_t table_0_header_legacy_attrib[]
static int write_packet(AVFormatContext *s, AVPacket *pkt)
const ff_asf_guid ff_format_videoinfo2
const ff_asf_guid ff_wtv_guid
static void write_table_entries_events(AVFormatContext *s)
int64_t last_chunk_pos
last chunk position
int64_t first_index_pos
first index_chunk position
int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc, int flags)
Write WAVEFORMAT header structure.
void * priv_data
Format private data.
const ff_asf_guid ff_format_none
#define AV_DICT_IGNORE_SUFFIX
Return first entry in a dictionary whose first part corresponds to the search key, ignoring the suffix of the found key string.
static void write_tag_int32(AVIOContext *pb, const char *key, int value)
const ff_asf_guid ff_stream1_guid
static void write_metadata_header(AVIOContext *pb, int type, const char *key, int value_size)
This structure stores compressed data.
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
#define AV_NOPTS_VALUE
Undefined timestamp value.