annotate ffmpeg/libavformat/wtvenc.c @ 13:844d341cf643 tip

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