Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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