You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

718 lines
22KB

  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. * @file
  23. * Windows Television (WTV) demuxer
  24. * @author Zhentan Feng <spyfeng at gmail dot com>
  25. */
  26. #include "libavutil/intreadwrite.h"
  27. #include "libavutil/avassert.h"
  28. #include "avformat.h"
  29. #include "internal.h"
  30. #include "wtv.h"
  31. #include "asf.h"
  32. #define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS)
  33. #define INDEX_BASE 0x2
  34. #define MAX_NB_INDEX 10
  35. /* declare utf16le strings */
  36. #define _ , 0,
  37. static const uint8_t timeline_table_0_header_events[] =
  38. {'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};
  39. static const uint8_t table_0_header_legacy_attrib[] =
  40. {'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};
  41. static const uint8_t table_0_redirector_legacy_attrib[] =
  42. {'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};
  43. static const uint8_t table_0_header_time[] =
  44. {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'t'_'i'_'m'_'e', 0};
  45. static const uint8_t legacy_attrib[] =
  46. {'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
  47. #undef _
  48. static const ff_asf_guid sub_wtv_guid =
  49. {0x8C,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
  50. enum WtvFileIndex {
  51. WTV_TIMELINE_TABLE_0_HEADER_EVENTS = 0,
  52. WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS,
  53. WTV_TIMELINE,
  54. WTV_TABLE_0_HEADER_LEGACY_ATTRIB,
  55. WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB,
  56. WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB,
  57. WTV_TABLE_0_HEADER_TIME,
  58. WTV_TABLE_0_ENTRIES_TIME,
  59. WTV_FILES
  60. };
  61. typedef struct {
  62. int64_t length;
  63. const void *header;
  64. int depth;
  65. int first_sector;
  66. } WtvFile;
  67. typedef struct {
  68. int64_t pos;
  69. int64_t serial;
  70. const ff_asf_guid * guid;
  71. int stream_id;
  72. } WtvChunkEntry;
  73. typedef struct {
  74. int64_t timeline_start_pos;
  75. WtvFile file[WTV_FILES];
  76. int64_t serial; /** chunk serial number */
  77. int64_t last_chunk_pos; /** last chunk position */
  78. int64_t frame_nb;
  79. WtvChunkEntry index[MAX_NB_INDEX];
  80. int nb_index;
  81. int first_video_flag;
  82. int64_t sync_pos;
  83. } WtvContext;
  84. typedef int WTVHeaderWriteFunc(AVIOContext *pb);
  85. typedef struct {
  86. const uint8_t *header;
  87. int header_size;
  88. WTVHeaderWriteFunc *write_header;
  89. } WTVRootEntryTable;
  90. static int write_pad(AVIOContext *pb, int size)
  91. {
  92. for (; size > 0; size--)
  93. avio_w8(pb, 0);
  94. return 0;
  95. }
  96. static const ff_asf_guid *get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid)
  97. {
  98. int i;
  99. for (i = 0; av_guid[i].id != AV_CODEC_ID_NONE; i++) {
  100. if (id == av_guid[i].id)
  101. return &(av_guid[i].guid);
  102. }
  103. return NULL;
  104. }
  105. /**
  106. * Write chunk header. If header chunk (0x80000000 set) then add to list of header chunks
  107. */
  108. static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id)
  109. {
  110. WtvContext *wctx = s->priv_data;
  111. AVIOContext *pb = s->pb;
  112. wctx->last_chunk_pos = avio_tell(pb) - wctx->timeline_start_pos;
  113. ff_put_guid(pb, guid);
  114. avio_wl32(pb, 32 + length);
  115. avio_wl32(pb, stream_id);
  116. avio_wl64(pb, wctx->serial);
  117. if ((stream_id & 0x80000000) && guid != &ff_index_guid) {
  118. WtvChunkEntry *t = wctx->index + wctx->nb_index;
  119. av_assert0(wctx->nb_index < MAX_NB_INDEX);
  120. t->pos = wctx->last_chunk_pos;
  121. t->serial = wctx->serial;
  122. t->guid = guid;
  123. t->stream_id = stream_id & 0x3FFFFFFF;
  124. wctx->nb_index++;
  125. }
  126. }
  127. static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id)
  128. {
  129. WtvContext *wctx = s->priv_data;
  130. AVIOContext *pb = s->pb;
  131. int64_t last_chunk_pos = wctx->last_chunk_pos;
  132. write_chunk_header(s, guid, 0, stream_id); // length updated later
  133. avio_wl64(pb, last_chunk_pos);
  134. }
  135. static void finish_chunk_noindex(AVFormatContext *s)
  136. {
  137. WtvContext *wctx = s->priv_data;
  138. AVIOContext *pb = s->pb;
  139. // update the chunk_len field and pad.
  140. int64_t chunk_len = avio_tell(pb) - (wctx->last_chunk_pos + wctx->timeline_start_pos);
  141. avio_seek(pb, -(chunk_len - 16), SEEK_CUR);
  142. avio_wl32(pb, chunk_len);
  143. avio_seek(pb, chunk_len - (16 + 4), SEEK_CUR);
  144. write_pad(pb, WTV_PAD8(chunk_len) - chunk_len);
  145. wctx->serial++;
  146. }
  147. static void write_index(AVFormatContext *s)
  148. {
  149. AVIOContext *pb = s->pb;
  150. WtvContext *wctx = s->priv_data;
  151. int i;
  152. write_chunk_header2(s, &ff_index_guid, 0x80000000);
  153. avio_wl32(pb, 0);
  154. avio_wl32(pb, 0);
  155. for (i = 0; i < wctx->nb_index; i++) {
  156. WtvChunkEntry *t = wctx->index + i;
  157. ff_put_guid(pb, t->guid);
  158. avio_wl64(pb, t->pos);
  159. avio_wl32(pb, t->stream_id);
  160. avio_wl32(pb, 0); // checksum?
  161. avio_wl64(pb, t->serial);
  162. }
  163. wctx->nb_index = 0; // reset index
  164. finish_chunk_noindex(s);
  165. }
  166. static void finish_chunk(AVFormatContext *s)
  167. {
  168. WtvContext *wctx = s->priv_data;
  169. finish_chunk_noindex(s);
  170. if (wctx->nb_index == MAX_NB_INDEX)
  171. write_index(s);
  172. }
  173. static int write_stream_codec_info(AVFormatContext *s, AVStream *st)
  174. {
  175. WtvContext *wctx = s->priv_data;
  176. const ff_asf_guid *g, *media_type, *format_type;
  177. AVIOContext *pb = s->pb;
  178. int64_t hdr_pos_start;
  179. int hdr_size = 0;
  180. if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  181. g = get_codec_guid(st->codec->codec_id, ff_video_guids);
  182. media_type = &ff_mediatype_video;
  183. format_type = &ff_format_mpeg2_video;
  184. } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
  185. g = get_codec_guid(st->codec->codec_id, ff_codec_wav_guids);
  186. media_type = &ff_mediatype_audio;
  187. format_type = &ff_format_waveformatex;
  188. } else {
  189. av_log(s, AV_LOG_ERROR, "unknown codec_type (0x%x)\n", st->codec->codec_type);
  190. return -1;
  191. }
  192. if (g == NULL) {
  193. av_log(s, AV_LOG_ERROR, "can't get video codec_id (0x%x) guid.\n", st->codec->codec_id);
  194. return -1;
  195. }
  196. ff_put_guid(pb, media_type); // mediatype
  197. ff_put_guid(pb, &ff_mediasubtype_cpfilters_processed); // subtype
  198. write_pad(pb, 12);
  199. ff_put_guid(pb,&ff_format_cpfilters_processed); // format type
  200. avio_wl32(pb, 0); // size
  201. hdr_pos_start = avio_tell(pb);
  202. if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  203. if (wctx->first_video_flag) {
  204. write_pad(pb, 216); //The size is sensitive.
  205. wctx->first_video_flag = 0;
  206. } else {
  207. write_pad(pb, 72); // aspect ratio
  208. ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0);
  209. }
  210. } else {
  211. ff_put_wav_header(pb, st->codec);
  212. }
  213. hdr_size = avio_tell(pb) - hdr_pos_start;
  214. // seek back write hdr_size
  215. avio_seek(pb, -(hdr_size + 4), SEEK_CUR);
  216. avio_wl32(pb, hdr_size + 32);
  217. avio_seek(pb, hdr_size, SEEK_CUR);
  218. ff_put_guid(pb, g); // actual_subtype
  219. ff_put_guid(pb, format_type); // actual_formattype
  220. return 0;
  221. }
  222. static int write_stream_codec(AVFormatContext *s, AVStream * st)
  223. {
  224. AVIOContext *pb = s->pb;
  225. int ret;
  226. write_chunk_header2(s, &ff_stream1_guid, 0x80000000 | 0x01);
  227. avio_wl32(pb, 0x01);
  228. write_pad(pb, 4);
  229. write_pad(pb, 4);
  230. ret = write_stream_codec_info(s, st);
  231. if (ret < 0) {
  232. av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
  233. return -1;
  234. }
  235. finish_chunk(s);
  236. return 0;
  237. }
  238. static void write_sync(AVFormatContext *s)
  239. {
  240. AVIOContext *pb = s->pb;
  241. WtvContext *wctx = s->priv_data;
  242. int64_t last_chunk_pos = wctx->last_chunk_pos;
  243. wctx->sync_pos = avio_tell(pb) - wctx->timeline_start_pos;
  244. write_chunk_header(s, &ff_sync_guid, 0x18, 0);
  245. write_pad(pb, 24);
  246. finish_chunk(s);
  247. wctx->last_chunk_pos = last_chunk_pos;
  248. }
  249. static void write_DSATTRIB_TRANSPORT_PROPERTIES_init(AVFormatContext *s, int stream_index)
  250. {
  251. AVIOContext *pb = s->pb;
  252. write_chunk_header2(s, &ff_DSATTRIB_TRANSPORT_PROPERTIES, 0x80000000 | stream_index);
  253. avio_wl64(pb, stream_index);
  254. avio_wl64(pb, -1);
  255. avio_wl64(pb, 0);
  256. finish_chunk(s);
  257. }
  258. static int write_stream_data(AVFormatContext *s, AVStream *st, int flag)
  259. {
  260. AVIOContext *pb = s->pb;
  261. int ret;
  262. if (!flag) {
  263. write_chunk_header2(s, &ff_SBE2_STREAM_DESC_EVENT, 0x80000000 | (st->index + INDEX_BASE));
  264. avio_wl32(pb, 0x00000001);
  265. avio_wl32(pb, st->index + INDEX_BASE); //stream_id
  266. avio_wl32(pb, 0x00000001);
  267. write_pad(pb, 8);
  268. } else {
  269. write_chunk_header2(s, &ff_stream2_guid, 0x80000000 | (st->index + INDEX_BASE));
  270. write_pad(pb, 4);
  271. }
  272. ret = write_stream_codec_info(s, st);
  273. if (ret < 0) {
  274. av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
  275. return -1;
  276. }
  277. finish_chunk(s);
  278. avpriv_set_pts_info(st, 64, 1, 10000000);
  279. return 0;
  280. }
  281. static int write_header(AVFormatContext *s)
  282. {
  283. AVIOContext *pb = s->pb;
  284. WtvContext *wctx = s->priv_data;
  285. int i, pad, ret;
  286. AVStream *st;
  287. ff_put_guid(pb, &ff_wtv_guid);
  288. ff_put_guid(pb, &sub_wtv_guid);
  289. avio_wl32(pb, 0x01);
  290. avio_wl32(pb, 0x02);
  291. avio_wl32(pb, 1 << WTV_SECTOR_BITS);
  292. avio_wl32(pb, 1 << WTV_BIGSECTOR_BITS);
  293. //write initial root fields
  294. avio_wl32(pb, 0); // root_size, update later
  295. write_pad(pb, 4);
  296. avio_wl32(pb, 0); // root_sector, update it later.
  297. write_pad(pb, 32);
  298. avio_wl32(pb, 0); // file ends pointer, update it later.
  299. pad = (1 << WTV_SECTOR_BITS) - avio_tell(pb);
  300. write_pad(pb, pad);
  301. wctx->timeline_start_pos = avio_tell(pb);
  302. wctx->serial = 1;
  303. wctx->last_chunk_pos = -1;
  304. wctx->first_video_flag = 1;
  305. for (i = 0; i < s->nb_streams; i++) {
  306. st = s->streams[i];
  307. ret = write_stream_codec(s, st);
  308. if (ret < 0) {
  309. av_log(s, AV_LOG_ERROR, "write stream codec failed codec_type(0x%x)\n", st->codec->codec_type);
  310. return -1;
  311. }
  312. if (i + 1 < s->nb_streams) {
  313. write_sync(s);
  314. }
  315. }
  316. for (i = 0; i < s->nb_streams; i++) {
  317. st = s->streams[i];
  318. ret = write_stream_data(s, st, 0);
  319. if (ret < 0) {
  320. av_log(s, AV_LOG_ERROR, "write stream data failed codec_type(0x%x)\n", st->codec->codec_type);
  321. return -1;
  322. }
  323. ret = write_stream_data(s, st, 1);
  324. if (ret < 0) {
  325. av_log(s, AV_LOG_ERROR, "write stream2 data failed codec_type(0x%x)\n", st->codec->codec_type);
  326. return -1;
  327. }
  328. }
  329. for (i = 0; i < s->nb_streams; i++)
  330. write_DSATTRIB_TRANSPORT_PROPERTIES_init(s, INDEX_BASE + i);
  331. if (wctx->nb_index)
  332. write_index(s);
  333. return 0;
  334. }
  335. static void write_timestamp(AVFormatContext *s, AVPacket *pkt)
  336. {
  337. AVIOContext *pb = s->pb;
  338. WtvContext *wctx = s->priv_data;
  339. AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
  340. int flag = 0;
  341. int64_t frame_number = 0;
  342. if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
  343. wctx->frame_nb++;
  344. frame_number = wctx->frame_nb;
  345. flag = pkt->flags & AV_PKT_FLAG_KEY ? 1 : 0;
  346. }
  347. write_chunk_header(s, &ff_timestamp_guid, 56, 0x40000000 | (INDEX_BASE + pkt->stream_index));
  348. write_pad(pb, 8);
  349. avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
  350. avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
  351. avio_wl64(pb, frame_number);
  352. avio_wl64(pb, 0);
  353. avio_wl64(pb, flag);
  354. avio_wl64(pb, 0);
  355. }
  356. static int write_packet(AVFormatContext *s, AVPacket *pkt)
  357. {
  358. AVIOContext *pb = s->pb;
  359. WtvContext *wctx = s->priv_data;
  360. // write timestamp chunk
  361. write_timestamp(s, pkt);
  362. write_chunk_header(s, &ff_data_guid, pkt->size, INDEX_BASE + pkt->stream_index);
  363. avio_write(pb, pkt->data, pkt->size);
  364. write_pad(pb, WTV_PAD8(pkt->size) - pkt->size);
  365. wctx->serial++;
  366. avio_flush(pb);
  367. return 0;
  368. }
  369. static int write_table0_header_events(AVIOContext *pb)
  370. {
  371. avio_wl32(pb, 0x10);
  372. write_pad(pb, 84);
  373. avio_wl64(pb, 0x32);
  374. return 96;
  375. }
  376. static int write_table0_header_legacy_attrib(AVIOContext *pb)
  377. {
  378. int pad = 0;
  379. avio_wl32(pb, 0xFFFFFFFF);
  380. write_pad(pb, 12);
  381. avio_write(pb, legacy_attrib, sizeof(legacy_attrib));
  382. pad = WTV_PAD8(sizeof(legacy_attrib)) - sizeof(legacy_attrib);
  383. write_pad(pb, pad);
  384. write_pad(pb, 32);
  385. return 48 + WTV_PAD8(sizeof(legacy_attrib));
  386. }
  387. static int write_table0_header_time(AVIOContext *pb)
  388. {
  389. avio_wl32(pb, 0x10);
  390. write_pad(pb, 76);
  391. avio_wl64(pb, 0x40);
  392. return 88;
  393. }
  394. static const WTVRootEntryTable wtv_root_entry_table[] = {
  395. { timeline_table_0_header_events, sizeof(timeline_table_0_header_events), write_table0_header_events},
  396. { ff_timeline_table_0_entries_Events_le16, sizeof(ff_timeline_table_0_entries_Events_le16), NULL},
  397. { ff_timeline_le16, sizeof(ff_timeline_le16), NULL},
  398. { table_0_header_legacy_attrib, sizeof(table_0_header_legacy_attrib), write_table0_header_legacy_attrib},
  399. { ff_table_0_entries_legacy_attrib_le16, sizeof(ff_table_0_entries_legacy_attrib_le16), NULL},
  400. { table_0_redirector_legacy_attrib, sizeof(table_0_redirector_legacy_attrib), NULL},
  401. { table_0_header_time, sizeof(table_0_header_time), write_table0_header_time},
  402. { ff_table_0_entries_time_le16, sizeof(ff_table_0_entries_time_le16), NULL},
  403. };
  404. static int write_root_table(AVFormatContext *s, int64_t sector_pos)
  405. {
  406. AVIOContext *pb = s->pb;
  407. WtvContext *wctx = s->priv_data;
  408. int size, pad;
  409. int i;
  410. const WTVRootEntryTable *h = wtv_root_entry_table;
  411. for (i = 0; i < sizeof(wtv_root_entry_table)/sizeof(WTVRootEntryTable); i++, h++) {
  412. WtvFile *w = &wctx->file[i];
  413. int filename_padding = WTV_PAD8(h->header_size) - h->header_size;
  414. WTVHeaderWriteFunc *write = h->write_header;
  415. int len = 0;
  416. int64_t len_pos;
  417. ff_put_guid(pb, &ff_dir_entry_guid);
  418. len_pos = avio_tell(pb);
  419. avio_wl16(pb, 40 + h->header_size + filename_padding + 8); // maybe updated later
  420. write_pad(pb, 6);
  421. avio_wl64(pb, write ? 0 : w->length);// maybe update later
  422. avio_wl32(pb, (h->header_size + filename_padding) >> 1);
  423. write_pad(pb, 4);
  424. avio_write(pb, h->header, h->header_size);
  425. write_pad(pb, filename_padding);
  426. if (write) {
  427. len = write(pb);
  428. // update length field
  429. avio_seek(pb, len_pos, SEEK_SET);
  430. avio_wl64(pb, 40 + h->header_size + filename_padding + len);
  431. avio_wl64(pb, len |(1ULL<<62) | (1ULL<<60));
  432. avio_seek(pb, 8 + h->header_size + filename_padding + len, SEEK_CUR);
  433. } else {
  434. avio_wl32(pb, w->first_sector);
  435. avio_wl32(pb, w->depth);
  436. }
  437. }
  438. // caculate root table size
  439. size = avio_tell(pb) - sector_pos;
  440. pad = WTV_SECTOR_SIZE- size;
  441. write_pad(pb, pad);
  442. return size;
  443. }
  444. static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift)
  445. {
  446. int i;
  447. for (i = 0; i < nb_sectors; i++) {
  448. avio_wl32(pb, start_sector + (i << shift));
  449. }
  450. // pad left sector pointer size
  451. write_pad(pb, WTV_SECTOR_SIZE - ((nb_sectors << 2) % WTV_SECTOR_SIZE));
  452. }
  453. static int write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth)
  454. {
  455. int64_t start_sector = start_pos >> WTV_SECTOR_BITS;
  456. int shift = sector_bits - WTV_SECTOR_BITS;
  457. int64_t fat = avio_tell(s->pb);
  458. write_fat(s->pb, start_sector, nb_sectors, shift);
  459. if (depth == 2) {
  460. int64_t start_sector1 = fat >> WTV_SECTOR_BITS;
  461. int nb_sectors1 = ((nb_sectors << 2) + WTV_SECTOR_SIZE - 1) / WTV_SECTOR_SIZE;
  462. int64_t fat1 = avio_tell(s->pb);
  463. write_fat(s->pb, start_sector1, nb_sectors1, 0);
  464. return fat1;
  465. }
  466. return fat;
  467. }
  468. static void write_table_entries_events(AVFormatContext *s)
  469. {
  470. AVIOContext *pb = s->pb;
  471. WtvContext *wctx = s->priv_data;
  472. //FIXME: output frame_nb, position pairs.
  473. //We only set the first sync_chunk position here.
  474. avio_wl64(pb, 0x2); avio_wl64(pb, wctx->sync_pos);
  475. }
  476. static void write_tag(AVIOContext *pb, const char *key, const char *value)
  477. {
  478. ff_put_guid(pb, &ff_metadata_guid);
  479. avio_wl32(pb, 1);
  480. avio_wl32(pb, strlen(value)*2 + 2);
  481. avio_put_str16le(pb, key);
  482. avio_put_str16le(pb, value);
  483. }
  484. static void write_table_entries_attrib(AVFormatContext *s)
  485. {
  486. AVDictionaryEntry *tag = 0;
  487. //FIXME: translate special tags (e.g. WM/Bitrate) to binary representation
  488. ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
  489. while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
  490. write_tag(s->pb, tag->key, tag->value);
  491. }
  492. static void write_table_redirector_legacy_attrib(AVFormatContext *s)
  493. {
  494. AVIOContext *pb = s->pb;
  495. AVDictionaryEntry *tag = 0;
  496. int64_t pos = 0;
  497. //FIXME: translate special tags to binary representation
  498. while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  499. avio_wl64(pb, pos);
  500. pos += 16 + 4 + 4 + strlen(tag->key)*2 + 2 + strlen(tag->value)*2 + 2;
  501. }
  502. }
  503. /**
  504. * Pad the remainder of a file
  505. * Write out fat table
  506. * @return <0 on error
  507. */
  508. static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos)
  509. {
  510. WtvContext *wctx = s->priv_data;
  511. AVIOContext *pb = s->pb;
  512. WtvFile *w = &wctx->file[index];
  513. int64_t end_pos = avio_tell(pb);
  514. int sector_bits, nb_sectors, pad;
  515. av_assert0(index < WTV_FILES);
  516. w->length = (end_pos - start_pos);
  517. // determine optimal fat table depth, sector_bits, nb_sectors
  518. if (w->length <= WTV_SECTOR_SIZE) {
  519. w->depth = 0;
  520. sector_bits = WTV_SECTOR_BITS;
  521. } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
  522. w->depth = 1;
  523. sector_bits = WTV_SECTOR_BITS;
  524. } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
  525. w->depth = 1;
  526. sector_bits = WTV_BIGSECTOR_BITS;
  527. } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
  528. w->depth = 2;
  529. sector_bits = WTV_SECTOR_BITS;
  530. } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
  531. w->depth = 2;
  532. sector_bits = WTV_BIGSECTOR_BITS;
  533. } else {
  534. av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (%"PRIi64" bytes)\n", w->length);
  535. return -1;
  536. }
  537. // determine the nb_sectors
  538. nb_sectors = (int)(w->length >> sector_bits);
  539. // pad sector of timeline
  540. pad = (1 << sector_bits) - (w->length % (1 << sector_bits));
  541. if (pad) {
  542. nb_sectors++;
  543. write_pad(pb, pad);
  544. }
  545. //write fat table
  546. if (w->depth > 0) {
  547. w->first_sector = write_fat_sector(s, start_pos, nb_sectors, sector_bits, w->depth);
  548. } else {
  549. w->first_sector = start_pos;
  550. }
  551. w->first_sector >>= WTV_SECTOR_BITS;
  552. w->length |= 1ULL<<60;
  553. if (sector_bits == WTV_SECTOR_BITS)
  554. w->length |= 1ULL<<63;
  555. return 0;
  556. }
  557. static int write_trailer(AVFormatContext *s)
  558. {
  559. WtvContext *wctx = s->priv_data;
  560. AVIOContext *pb = s->pb;
  561. int root_size;
  562. int64_t sector_pos;
  563. int64_t start_pos, file_end_pos;
  564. if (finish_file(s, WTV_TIMELINE, wctx->timeline_start_pos) < 0)
  565. return -1;
  566. start_pos = avio_tell(pb);
  567. write_table_entries_events(s);
  568. if (finish_file(s, WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS, start_pos) < 0)
  569. return -1;
  570. start_pos = avio_tell(pb);
  571. write_table_entries_attrib(s);
  572. if (finish_file(s, WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB, start_pos) < 0)
  573. return -1;
  574. start_pos = avio_tell(pb);
  575. write_table_redirector_legacy_attrib(s);
  576. if (finish_file(s, WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB, start_pos) < 0)
  577. return -1;
  578. start_pos = avio_tell(pb);
  579. //FIXME: output timestamp, frame_nb pairs here.
  580. if (finish_file(s, WTV_TABLE_0_ENTRIES_TIME, start_pos) < 0)
  581. return -1;
  582. // write root table
  583. sector_pos = avio_tell(pb);
  584. root_size = write_root_table(s, sector_pos);
  585. file_end_pos = avio_tell(pb);
  586. // update root value
  587. avio_seek(pb, 0x30, SEEK_SET);
  588. avio_wl32(pb, root_size);
  589. avio_seek(pb, 4, SEEK_CUR);
  590. avio_wl32(pb, sector_pos >> WTV_SECTOR_BITS);
  591. avio_seek(pb, 0x5c, SEEK_SET);
  592. avio_wl32(pb, file_end_pos >> WTV_SECTOR_BITS);
  593. avio_flush(pb);
  594. return 0;
  595. }
  596. AVOutputFormat ff_wtv_muxer = {
  597. .name = "wtv",
  598. .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
  599. .extensions = "wtv",
  600. .priv_data_size = sizeof(WtvContext),
  601. .audio_codec = AV_CODEC_ID_AC3,
  602. .video_codec = AV_CODEC_ID_MPEG2VIDEO,
  603. .write_header = write_header,
  604. .write_packet = write_packet,
  605. .write_trailer = write_trailer,
  606. .codec_tag = (const AVCodecTag* const []){ ff_codec_bmp_tags,
  607. ff_codec_wav_tags, 0 },
  608. };