00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00028 #include "libavutil/intreadwrite.h"
00029 #include "libavutil/avassert.h"
00030 #include "avformat.h"
00031 #include "internal.h"
00032 #include "wtv.h"
00033 #include "asf.h"
00034
00035 #define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS)
00036 #define INDEX_BASE 0x2
00037 #define MAX_NB_INDEX 10
00038
00039
00040 #define _ , 0,
00041 static const uint8_t timeline_table_0_header_events[] =
00042 {'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};
00043 static const uint8_t table_0_header_legacy_attrib[] =
00044 {'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};
00045 static const uint8_t table_0_redirector_legacy_attrib[] =
00046 {'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};
00047 static const uint8_t table_0_header_time[] =
00048 {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'t'_'i'_'m'_'e', 0};
00049 static const uint8_t legacy_attrib[] =
00050 {'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
00051 #undef _
00052
00053 static const ff_asf_guid sub_wtv_guid =
00054 {0x8C,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
00055
00056 enum WtvFileIndex {
00057 WTV_TIMELINE_TABLE_0_HEADER_EVENTS = 0,
00058 WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS,
00059 WTV_TIMELINE,
00060 WTV_TABLE_0_HEADER_LEGACY_ATTRIB,
00061 WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB,
00062 WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB,
00063 WTV_TABLE_0_HEADER_TIME,
00064 WTV_TABLE_0_ENTRIES_TIME,
00065 WTV_FILES
00066 };
00067
00068 typedef struct {
00069 int64_t length;
00070 const void *header;
00071 int depth;
00072 int first_sector;
00073 } WtvFile;
00074
00075 typedef struct {
00076 int64_t pos;
00077 int64_t serial;
00078 const ff_asf_guid * guid;
00079 int stream_id;
00080 } WtvChunkEntry;
00081
00082 typedef struct {
00083 int64_t serial;
00084 int64_t value;
00085 } WtvSyncEntry;
00086
00087 typedef struct {
00088 int64_t timeline_start_pos;
00089 WtvFile file[WTV_FILES];
00090 int64_t serial;
00091 int64_t last_chunk_pos;
00092 int64_t last_timestamp_pos;
00093 int64_t first_index_pos;
00095 WtvChunkEntry index[MAX_NB_INDEX];
00096 int nb_index;
00097 int first_video_flag;
00098
00099 WtvSyncEntry *st_pairs;
00100 int nb_st_pairs;
00101 WtvSyncEntry *sp_pairs;
00102 int nb_sp_pairs;
00103
00104 int64_t last_pts;
00105 int64_t last_serial;
00106 } WtvContext;
00107
00108
00109 static void add_serial_pair(WtvSyncEntry ** list, int * count, int64_t serial, int64_t value)
00110 {
00111 int new_count = *count + 1;
00112 WtvSyncEntry *new_list = av_realloc(*list, new_count * sizeof(WtvSyncEntry));
00113 if (!new_list)
00114 return;
00115 new_list[*count] = (WtvSyncEntry){serial, value};
00116 *list = new_list;
00117 *count = new_count;
00118 }
00119
00120 typedef int WTVHeaderWriteFunc(AVIOContext *pb);
00121
00122 typedef struct {
00123 const uint8_t *header;
00124 int header_size;
00125 WTVHeaderWriteFunc *write_header;
00126 } WTVRootEntryTable;
00127
00128 static int write_pad(AVIOContext *pb, int size)
00129 {
00130 for (; size > 0; size--)
00131 avio_w8(pb, 0);
00132 return 0;
00133 }
00134
00135 static const ff_asf_guid *get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid)
00136 {
00137 int i;
00138 for (i = 0; av_guid[i].id != AV_CODEC_ID_NONE; i++) {
00139 if (id == av_guid[i].id)
00140 return &(av_guid[i].guid);
00141 }
00142 return NULL;
00143 }
00144
00148 static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id)
00149 {
00150 WtvContext *wctx = s->priv_data;
00151 AVIOContext *pb = s->pb;
00152
00153 wctx->last_chunk_pos = avio_tell(pb) - wctx->timeline_start_pos;
00154 ff_put_guid(pb, guid);
00155 avio_wl32(pb, 32 + length);
00156 avio_wl32(pb, stream_id);
00157 avio_wl64(pb, wctx->serial);
00158
00159 if ((stream_id & 0x80000000) && guid != &ff_index_guid) {
00160 WtvChunkEntry *t = wctx->index + wctx->nb_index;
00161 av_assert0(wctx->nb_index < MAX_NB_INDEX);
00162 t->pos = wctx->last_chunk_pos;
00163 t->serial = wctx->serial;
00164 t->guid = guid;
00165 t->stream_id = stream_id & 0x3FFFFFFF;
00166 wctx->nb_index++;
00167 }
00168 }
00169
00170 static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id)
00171 {
00172 WtvContext *wctx = s->priv_data;
00173 AVIOContext *pb = s->pb;
00174
00175 int64_t last_chunk_pos = wctx->last_chunk_pos;
00176 write_chunk_header(s, guid, 0, stream_id);
00177 avio_wl64(pb, last_chunk_pos);
00178 }
00179
00180 static void finish_chunk_noindex(AVFormatContext *s)
00181 {
00182 WtvContext *wctx = s->priv_data;
00183 AVIOContext *pb = s->pb;
00184
00185
00186 int64_t chunk_len = avio_tell(pb) - (wctx->last_chunk_pos + wctx->timeline_start_pos);
00187 avio_seek(pb, -(chunk_len - 16), SEEK_CUR);
00188 avio_wl32(pb, chunk_len);
00189 avio_seek(pb, chunk_len - (16 + 4), SEEK_CUR);
00190
00191 write_pad(pb, WTV_PAD8(chunk_len) - chunk_len);
00192 wctx->serial++;
00193 }
00194
00195 static void write_index(AVFormatContext *s)
00196 {
00197 AVIOContext *pb = s->pb;
00198 WtvContext *wctx = s->priv_data;
00199 int i;
00200
00201 write_chunk_header2(s, &ff_index_guid, 0x80000000);
00202 avio_wl32(pb, 0);
00203 avio_wl32(pb, 0);
00204
00205 for (i = 0; i < wctx->nb_index; i++) {
00206 WtvChunkEntry *t = wctx->index + i;
00207 ff_put_guid(pb, t->guid);
00208 avio_wl64(pb, t->pos);
00209 avio_wl32(pb, t->stream_id);
00210 avio_wl32(pb, 0);
00211 avio_wl64(pb, t->serial);
00212 }
00213 wctx->nb_index = 0;
00214 finish_chunk_noindex(s);
00215
00216 if (!wctx->first_index_pos)
00217 wctx->first_index_pos = wctx->last_chunk_pos;
00218 }
00219
00220 static void finish_chunk(AVFormatContext *s)
00221 {
00222 WtvContext *wctx = s->priv_data;
00223 finish_chunk_noindex(s);
00224 if (wctx->nb_index == MAX_NB_INDEX)
00225 write_index(s);
00226 }
00227
00228 static int write_stream_codec_info(AVFormatContext *s, AVStream *st)
00229 {
00230 WtvContext *wctx = s->priv_data;
00231 const ff_asf_guid *g, *media_type, *format_type;
00232 AVIOContext *pb = s->pb;
00233 int64_t hdr_pos_start;
00234 int hdr_size = 0;
00235
00236 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
00237 g = get_codec_guid(st->codec->codec_id, ff_video_guids);
00238 media_type = &ff_mediatype_video;
00239 format_type = &ff_format_mpeg2_video;
00240 } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
00241 g = get_codec_guid(st->codec->codec_id, ff_codec_wav_guids);
00242 media_type = &ff_mediatype_audio;
00243 format_type = &ff_format_waveformatex;
00244 } else {
00245 av_log(s, AV_LOG_ERROR, "unknown codec_type (0x%x)\n", st->codec->codec_type);
00246 return -1;
00247 }
00248
00249 if (g == NULL) {
00250 av_log(s, AV_LOG_ERROR, "can't get video codec_id (0x%x) guid.\n", st->codec->codec_id);
00251 return -1;
00252 }
00253
00254 ff_put_guid(pb, media_type);
00255 ff_put_guid(pb, &ff_mediasubtype_cpfilters_processed);
00256 write_pad(pb, 12);
00257 ff_put_guid(pb,&ff_format_cpfilters_processed);
00258 avio_wl32(pb, 0);
00259
00260 hdr_pos_start = avio_tell(pb);
00261 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
00262 if (wctx->first_video_flag) {
00263 write_pad(pb, 216);
00264 wctx->first_video_flag = 0;
00265 } else {
00266 write_pad(pb, 72);
00267 ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0);
00268 }
00269 } else {
00270 ff_put_wav_header(pb, st->codec);
00271 }
00272 hdr_size = avio_tell(pb) - hdr_pos_start;
00273
00274
00275 avio_seek(pb, -(hdr_size + 4), SEEK_CUR);
00276 avio_wl32(pb, hdr_size + 32);
00277 avio_seek(pb, hdr_size, SEEK_CUR);
00278 ff_put_guid(pb, g);
00279 ff_put_guid(pb, format_type);
00280
00281 return 0;
00282 }
00283
00284 static int write_stream_codec(AVFormatContext *s, AVStream * st)
00285 {
00286 AVIOContext *pb = s->pb;
00287 int ret;
00288 write_chunk_header2(s, &ff_stream1_guid, 0x80000000 | 0x01);
00289
00290 avio_wl32(pb, 0x01);
00291 write_pad(pb, 4);
00292 write_pad(pb, 4);
00293
00294 ret = write_stream_codec_info(s, st);
00295 if (ret < 0) {
00296 av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
00297 return -1;
00298 }
00299
00300 finish_chunk(s);
00301 return 0;
00302 }
00303
00304 static void write_sync(AVFormatContext *s)
00305 {
00306 AVIOContext *pb = s->pb;
00307 WtvContext *wctx = s->priv_data;
00308 int64_t last_chunk_pos = wctx->last_chunk_pos;
00309
00310 write_chunk_header(s, &ff_sync_guid, 0x18, 0);
00311 avio_wl64(pb, wctx->first_index_pos);
00312 avio_wl64(pb, wctx->last_timestamp_pos);
00313 avio_wl64(pb, 0);
00314
00315 finish_chunk(s);
00316 add_serial_pair(&wctx->sp_pairs, &wctx->nb_sp_pairs, wctx->serial, wctx->last_chunk_pos);
00317
00318 wctx->last_chunk_pos = last_chunk_pos;
00319 }
00320
00321 static int write_stream_data(AVFormatContext *s, AVStream *st)
00322 {
00323 AVIOContext *pb = s->pb;
00324 int ret;
00325
00326 write_chunk_header2(s, &ff_SBE2_STREAM_DESC_EVENT, 0x80000000 | (st->index + INDEX_BASE));
00327 avio_wl32(pb, 0x00000001);
00328 avio_wl32(pb, st->index + INDEX_BASE);
00329 avio_wl32(pb, 0x00000001);
00330 write_pad(pb, 8);
00331
00332 ret = write_stream_codec_info(s, st);
00333 if (ret < 0) {
00334 av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
00335 return -1;
00336 }
00337 finish_chunk(s);
00338
00339 avpriv_set_pts_info(st, 64, 1, 10000000);
00340
00341 return 0;
00342 }
00343
00344 static int write_header(AVFormatContext *s)
00345 {
00346 AVIOContext *pb = s->pb;
00347 WtvContext *wctx = s->priv_data;
00348 int i, pad, ret;
00349 AVStream *st;
00350
00351 wctx->last_chunk_pos = -1;
00352 wctx->last_timestamp_pos = -1;
00353
00354 ff_put_guid(pb, &ff_wtv_guid);
00355 ff_put_guid(pb, &sub_wtv_guid);
00356
00357 avio_wl32(pb, 0x01);
00358 avio_wl32(pb, 0x02);
00359 avio_wl32(pb, 1 << WTV_SECTOR_BITS);
00360 avio_wl32(pb, 1 << WTV_BIGSECTOR_BITS);
00361
00362
00363 avio_wl32(pb, 0);
00364 write_pad(pb, 4);
00365 avio_wl32(pb, 0);
00366
00367 write_pad(pb, 32);
00368 avio_wl32(pb, 0);
00369
00370 pad = (1 << WTV_SECTOR_BITS) - avio_tell(pb);
00371 write_pad(pb, pad);
00372
00373 wctx->timeline_start_pos = avio_tell(pb);
00374
00375 wctx->serial = 1;
00376 wctx->last_chunk_pos = -1;
00377 wctx->first_video_flag = 1;
00378
00379 for (i = 0; i < s->nb_streams; i++) {
00380 st = s->streams[i];
00381 ret = write_stream_codec(s, st);
00382 if (ret < 0) {
00383 av_log(s, AV_LOG_ERROR, "write stream codec failed codec_type(0x%x)\n", st->codec->codec_type);
00384 return -1;
00385 }
00386 if (!i)
00387 write_sync(s);
00388 }
00389
00390 for (i = 0; i < s->nb_streams; i++) {
00391 st = s->streams[i];
00392 ret = write_stream_data(s, st);
00393 if (ret < 0) {
00394 av_log(s, AV_LOG_ERROR, "write stream data failed codec_type(0x%x)\n", st->codec->codec_type);
00395 return -1;
00396 }
00397 }
00398
00399 if (wctx->nb_index)
00400 write_index(s);
00401
00402 return 0;
00403 }
00404
00405 static void write_timestamp(AVFormatContext *s, AVPacket *pkt)
00406 {
00407 AVIOContext *pb = s->pb;
00408 WtvContext *wctx = s->priv_data;
00409 AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
00410
00411 write_chunk_header(s, &ff_timestamp_guid, 56, 0x40000000 | (INDEX_BASE + pkt->stream_index));
00412 write_pad(pb, 8);
00413 avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
00414 avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
00415 avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
00416 avio_wl64(pb, 0);
00417 avio_wl64(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO && (pkt->flags & AV_PKT_FLAG_KEY) ? 1 : 0);
00418 avio_wl64(pb, 0);
00419
00420 wctx->last_timestamp_pos = wctx->last_chunk_pos;
00421 }
00422
00423 static int write_packet(AVFormatContext *s, AVPacket *pkt)
00424 {
00425 AVIOContext *pb = s->pb;
00426 WtvContext *wctx = s->priv_data;
00427
00428
00429 if (wctx->serial - (wctx->nb_sp_pairs ? wctx->sp_pairs[wctx->nb_sp_pairs - 1].serial : 0) >= 50)
00430 write_sync(s);
00431
00432
00433 if (pkt->pts != AV_NOPTS_VALUE && pkt->pts - (wctx->nb_st_pairs ? wctx->st_pairs[wctx->nb_st_pairs - 1].value : 0) >= 5000000)
00434 add_serial_pair(&wctx->st_pairs, &wctx->nb_st_pairs, wctx->serial, pkt->pts);
00435
00436 if (pkt->pts != AV_NOPTS_VALUE && pkt->pts > wctx->last_pts) {
00437 wctx->last_pts = pkt->pts;
00438 wctx->last_serial = wctx->serial;
00439 }
00440
00441
00442 write_timestamp(s, pkt);
00443
00444 write_chunk_header(s, &ff_data_guid, pkt->size, INDEX_BASE + pkt->stream_index);
00445 avio_write(pb, pkt->data, pkt->size);
00446 write_pad(pb, WTV_PAD8(pkt->size) - pkt->size);
00447
00448 wctx->serial++;
00449 avio_flush(pb);
00450 return 0;
00451 }
00452
00453 static int write_table0_header_events(AVIOContext *pb)
00454 {
00455 avio_wl32(pb, 0x10);
00456 write_pad(pb, 84);
00457 avio_wl64(pb, 0x32);
00458 return 96;
00459 }
00460
00461 static int write_table0_header_legacy_attrib(AVIOContext *pb)
00462 {
00463 int pad = 0;
00464 avio_wl32(pb, 0xFFFFFFFF);
00465 write_pad(pb, 12);
00466 avio_write(pb, legacy_attrib, sizeof(legacy_attrib));
00467 pad = WTV_PAD8(sizeof(legacy_attrib)) - sizeof(legacy_attrib);
00468 write_pad(pb, pad);
00469 write_pad(pb, 32);
00470 return 48 + WTV_PAD8(sizeof(legacy_attrib));
00471 }
00472
00473 static int write_table0_header_time(AVIOContext *pb)
00474 {
00475 avio_wl32(pb, 0x10);
00476 write_pad(pb, 76);
00477 avio_wl64(pb, 0x40);
00478 return 88;
00479 }
00480
00481 static const WTVRootEntryTable wtv_root_entry_table[] = {
00482 { timeline_table_0_header_events, sizeof(timeline_table_0_header_events), write_table0_header_events},
00483 { ff_timeline_table_0_entries_Events_le16, sizeof(ff_timeline_table_0_entries_Events_le16), NULL},
00484 { ff_timeline_le16, sizeof(ff_timeline_le16), NULL},
00485 { table_0_header_legacy_attrib, sizeof(table_0_header_legacy_attrib), write_table0_header_legacy_attrib},
00486 { ff_table_0_entries_legacy_attrib_le16, sizeof(ff_table_0_entries_legacy_attrib_le16), NULL},
00487 { table_0_redirector_legacy_attrib, sizeof(table_0_redirector_legacy_attrib), NULL},
00488 { table_0_header_time, sizeof(table_0_header_time), write_table0_header_time},
00489 { ff_table_0_entries_time_le16, sizeof(ff_table_0_entries_time_le16), NULL},
00490 };
00491
00492 static int write_root_table(AVFormatContext *s, int64_t sector_pos)
00493 {
00494 AVIOContext *pb = s->pb;
00495 WtvContext *wctx = s->priv_data;
00496 int size, pad;
00497 int i;
00498
00499 const WTVRootEntryTable *h = wtv_root_entry_table;
00500 for (i = 0; i < sizeof(wtv_root_entry_table)/sizeof(WTVRootEntryTable); i++, h++) {
00501 WtvFile *w = &wctx->file[i];
00502 int filename_padding = WTV_PAD8(h->header_size) - h->header_size;
00503 WTVHeaderWriteFunc *write = h->write_header;
00504 int len = 0;
00505 int64_t len_pos;
00506
00507 ff_put_guid(pb, &ff_dir_entry_guid);
00508 len_pos = avio_tell(pb);
00509 avio_wl16(pb, 40 + h->header_size + filename_padding + 8);
00510 write_pad(pb, 6);
00511 avio_wl64(pb, write ? 0 : w->length);
00512 avio_wl32(pb, (h->header_size + filename_padding) >> 1);
00513 write_pad(pb, 4);
00514
00515 avio_write(pb, h->header, h->header_size);
00516 write_pad(pb, filename_padding);
00517
00518 if (write) {
00519 len = write(pb);
00520
00521 avio_seek(pb, len_pos, SEEK_SET);
00522 avio_wl64(pb, 40 + h->header_size + filename_padding + len);
00523 avio_wl64(pb, len |(1ULL<<62) | (1ULL<<60));
00524 avio_seek(pb, 8 + h->header_size + filename_padding + len, SEEK_CUR);
00525 } else {
00526 avio_wl32(pb, w->first_sector);
00527 avio_wl32(pb, w->depth);
00528 }
00529 }
00530
00531
00532 size = avio_tell(pb) - sector_pos;
00533 pad = WTV_SECTOR_SIZE- size;
00534 write_pad(pb, pad);
00535
00536 return size;
00537 }
00538
00539 static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift)
00540 {
00541 int i;
00542 for (i = 0; i < nb_sectors; i++) {
00543 avio_wl32(pb, start_sector + (i << shift));
00544 }
00545
00546 write_pad(pb, WTV_SECTOR_SIZE - ((nb_sectors << 2) % WTV_SECTOR_SIZE));
00547 }
00548
00549 static int write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth)
00550 {
00551 int64_t start_sector = start_pos >> WTV_SECTOR_BITS;
00552 int shift = sector_bits - WTV_SECTOR_BITS;
00553
00554 int64_t fat = avio_tell(s->pb);
00555 write_fat(s->pb, start_sector, nb_sectors, shift);
00556
00557 if (depth == 2) {
00558 int64_t start_sector1 = fat >> WTV_SECTOR_BITS;
00559 int nb_sectors1 = ((nb_sectors << 2) + WTV_SECTOR_SIZE - 1) / WTV_SECTOR_SIZE;
00560 int64_t fat1 = avio_tell(s->pb);
00561
00562 write_fat(s->pb, start_sector1, nb_sectors1, 0);
00563 return fat1;
00564 }
00565
00566 return fat;
00567 }
00568
00569 static void write_table_entries_events(AVFormatContext *s)
00570 {
00571 AVIOContext *pb = s->pb;
00572 WtvContext *wctx = s->priv_data;
00573 int i;
00574 for (i = 0; i < wctx->nb_sp_pairs; i++) {
00575 avio_wl64(pb, wctx->sp_pairs[i].serial);
00576 avio_wl64(pb, wctx->sp_pairs[i].value);
00577 }
00578 }
00579
00580 static void write_table_entries_time(AVFormatContext *s)
00581 {
00582 AVIOContext *pb = s->pb;
00583 WtvContext *wctx = s->priv_data;
00584 int i;
00585 for (i = 0; i < wctx->nb_st_pairs; i++) {
00586 avio_wl64(pb, wctx->st_pairs[i].value);
00587 avio_wl64(pb, wctx->st_pairs[i].serial);
00588 }
00589 avio_wl64(pb, wctx->last_pts);
00590 avio_wl64(pb, wctx->last_serial);
00591 }
00592
00593 static void write_tag(AVIOContext *pb, const char *key, const char *value)
00594 {
00595 ff_put_guid(pb, &ff_metadata_guid);
00596 avio_wl32(pb, 1);
00597 avio_wl32(pb, strlen(value)*2 + 2);
00598 avio_put_str16le(pb, key);
00599 avio_put_str16le(pb, value);
00600 }
00601
00602 static void write_table_entries_attrib(AVFormatContext *s)
00603 {
00604 AVDictionaryEntry *tag = 0;
00605
00606
00607 ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
00608 while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
00609 write_tag(s->pb, tag->key, tag->value);
00610 }
00611
00612 static void write_table_redirector_legacy_attrib(AVFormatContext *s)
00613 {
00614 AVIOContext *pb = s->pb;
00615 AVDictionaryEntry *tag = 0;
00616 int64_t pos = 0;
00617
00618
00619 while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
00620 avio_wl64(pb, pos);
00621 pos += 16 + 4 + 4 + strlen(tag->key)*2 + 2 + strlen(tag->value)*2 + 2;
00622 }
00623 }
00624
00630 static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos)
00631 {
00632 WtvContext *wctx = s->priv_data;
00633 AVIOContext *pb = s->pb;
00634 WtvFile *w = &wctx->file[index];
00635 int64_t end_pos = avio_tell(pb);
00636 int sector_bits, nb_sectors, pad;
00637
00638 av_assert0(index < WTV_FILES);
00639
00640 w->length = (end_pos - start_pos);
00641
00642
00643 if (w->length <= WTV_SECTOR_SIZE) {
00644 w->depth = 0;
00645 sector_bits = WTV_SECTOR_BITS;
00646 } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
00647 w->depth = 1;
00648 sector_bits = WTV_SECTOR_BITS;
00649 } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
00650 w->depth = 1;
00651 sector_bits = WTV_BIGSECTOR_BITS;
00652 } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
00653 w->depth = 2;
00654 sector_bits = WTV_SECTOR_BITS;
00655 } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
00656 w->depth = 2;
00657 sector_bits = WTV_BIGSECTOR_BITS;
00658 } else {
00659 av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (%"PRIi64" bytes)\n", w->length);
00660 return -1;
00661 }
00662
00663
00664 nb_sectors = (int)(w->length >> sector_bits);
00665
00666
00667 pad = (1 << sector_bits) - (w->length % (1 << sector_bits));
00668 if (pad) {
00669 nb_sectors++;
00670 write_pad(pb, pad);
00671 }
00672
00673
00674 if (w->depth > 0) {
00675 w->first_sector = write_fat_sector(s, start_pos, nb_sectors, sector_bits, w->depth);
00676 } else {
00677 w->first_sector = start_pos;
00678 }
00679 w->first_sector >>= WTV_SECTOR_BITS;
00680
00681 w->length |= 1ULL<<60;
00682 if (sector_bits == WTV_SECTOR_BITS)
00683 w->length |= 1ULL<<63;
00684
00685 return 0;
00686 }
00687
00688 static int write_trailer(AVFormatContext *s)
00689 {
00690 WtvContext *wctx = s->priv_data;
00691 AVIOContext *pb = s->pb;
00692 int root_size;
00693 int64_t sector_pos;
00694 int64_t start_pos, file_end_pos;
00695
00696 if (finish_file(s, WTV_TIMELINE, wctx->timeline_start_pos) < 0)
00697 return -1;
00698
00699 start_pos = avio_tell(pb);
00700 write_table_entries_events(s);
00701 if (finish_file(s, WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS, start_pos) < 0)
00702 return -1;
00703
00704 start_pos = avio_tell(pb);
00705 write_table_entries_attrib(s);
00706 if (finish_file(s, WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB, start_pos) < 0)
00707 return -1;
00708
00709 start_pos = avio_tell(pb);
00710 write_table_redirector_legacy_attrib(s);
00711 if (finish_file(s, WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB, start_pos) < 0)
00712 return -1;
00713
00714 start_pos = avio_tell(pb);
00715 write_table_entries_time(s);
00716 if (finish_file(s, WTV_TABLE_0_ENTRIES_TIME, start_pos) < 0)
00717 return -1;
00718
00719
00720 sector_pos = avio_tell(pb);
00721 root_size = write_root_table(s, sector_pos);
00722
00723 file_end_pos = avio_tell(pb);
00724
00725 avio_seek(pb, 0x30, SEEK_SET);
00726 avio_wl32(pb, root_size);
00727 avio_seek(pb, 4, SEEK_CUR);
00728 avio_wl32(pb, sector_pos >> WTV_SECTOR_BITS);
00729 avio_seek(pb, 0x5c, SEEK_SET);
00730 avio_wl32(pb, file_end_pos >> WTV_SECTOR_BITS);
00731
00732 avio_flush(pb);
00733
00734 av_free(wctx->sp_pairs);
00735 av_free(wctx->st_pairs);
00736 return 0;
00737 }
00738
00739 AVOutputFormat ff_wtv_muxer = {
00740 .name = "wtv",
00741 .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
00742 .extensions = "wtv",
00743 .priv_data_size = sizeof(WtvContext),
00744 .audio_codec = AV_CODEC_ID_AC3,
00745 .video_codec = AV_CODEC_ID_MPEG2VIDEO,
00746 .write_header = write_header,
00747 .write_packet = write_packet,
00748 .write_trailer = write_trailer,
00749 .codec_tag = (const AVCodecTag* const []){ ff_codec_bmp_tags,
00750 ff_codec_wav_tags, 0 },
00751 };