FFmpeg
wtvenc.c
Go to the documentation of this file.
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,
43  {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0};
45  {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
47  {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'r'_'e'_'d'_'i'_'r'_'e'_'c'_'t'_'o'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
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 
67 };
68 
69 typedef struct {
70  int64_t length;
71  const void *header;
72  int depth;
74 } WtvFile;
75 
76 typedef struct {
77  int64_t pos;
78  int64_t serial;
79  const ff_asf_guid * guid;
80  int stream_id;
82 
83 typedef struct {
84  int64_t serial;
85  int64_t value;
86 } WtvSyncEntry;
87 
88 typedef struct {
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 
97  int nb_index;
99 
100  WtvSyncEntry *st_pairs; /* (serial, timestamp) pairs */
102  WtvSyncEntry *sp_pairs; /* (serial, position) pairs */
104 
105  int64_t last_pts;
106  int64_t last_serial;
107 
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 
124 
125 typedef struct {
126  const uint8_t *header;
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;
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 
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 
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
203 
204  if (!wctx->first_index_pos)
205  wctx->first_index_pos = wctx->last_chunk_pos;
206 }
207 
209 {
210  WtvContext *wctx = s->priv_data;
212  if (wctx->nb_index == MAX_NB_INDEX)
213  write_index(s);
214 }
215 
217 {
218  AVRational dar = av_mul_q(st->sample_aspect_ratio, (AVRational){st->codecpar->width, st->codecpar->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->codecpar->width);
226  avio_wl32(pb, st->codecpar->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->codecpar->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->codecpar, 0, 1);
245 
247  int padding = (st->codecpar->extradata_size & 3) ? 4 - (st->codecpar->extradata_size & 3) : 0;
248  /* MPEG2VIDEOINFO */
249  avio_wl32(pb, 0);
250  avio_wl32(pb, st->codecpar->extradata_size + padding);
251  avio_wl32(pb, -1);
252  avio_wl32(pb, -1);
253  avio_wl32(pb, 0);
255  ffio_fill(pb, 0, padding);
256  }
257 }
258 
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->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
269  media_type = &ff_mediatype_video;
271  tags = ff_codec_bmp_tags;
272  } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
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->codecpar->codec_type);
279  return -1;
280  }
281 
282  ff_put_guid(pb, media_type); // mediatype
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->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
290  put_videoinfoheader2(pb, st);
291  } else {
292  if (ff_put_wav_header(s, pb, st->codecpar, 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->codecpar->codec_id);
305  if (!tag) {
306  av_log(s, AV_LOG_ERROR, "unsupported codec_id (0x%x)\n", st->codecpar->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 
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->codecpar->codec_type);
330  return -1;
331  }
332 
333  finish_chunk(s);
334  return 0;
335 }
336 
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 
355 {
356  AVIOContext *pb = s->pb;
357  int ret;
358 
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->codecpar->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 
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);
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->codecpar->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->codecpar->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->codecpar->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->codecpar->codec_type);
432  return -1;
433  }
434  }
435 
436  if (wctx->nb_index)
437  write_index(s);
438 
439  return 0;
440 }
441 
443 {
444  AVIOContext *pb = s->pb;
445  WtvContext *wctx = s->priv_data;
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, par->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 
461 {
462  AVIOContext *pb = s->pb;
463  WtvContext *wctx = s->priv_data;
464  AVStream *st = s->streams[pkt->stream_index];
465 
466  if (st->codecpar->codec_id == AV_CODEC_ID_MJPEG && !wctx->thumbnail.size) {
467  av_packet_ref(&wctx->thumbnail, pkt);
468  return 0;
469  } else if (st->codecpar->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 
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 
500 {
501  avio_wl32(pb, 0x10);
502  write_pad(pb, 84);
503  avio_wl64(pb, 0x32);
504  return 96;
505 }
506 
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 
520 {
521  avio_wl32(pb, 0x10);
522  write_pad(pb, 76);
523  avio_wl64(pb, 0x40);
524  return 88;
525 }
526 
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 
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 
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 
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 
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 {
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 
665 {
666  return strlen("image/jpeg")*2 + 2 + 1 + (e ? strlen(e->value)*2 : 0) + 2 + 4 + pkt->size;
667 }
668 
670 {
671  WtvContext *wctx = s->priv_data;
672  AVIOContext *pb = s->pb;
673  AVDictionaryEntry *tag = 0;
674 
676  //FIXME: translate special tags (e.g. WM/Bitrate) to binary representation
678  while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
679  write_tag(pb, tag->key, tag->value);
680 
681  if (wctx->thumbnail.size) {
682  AVStream *st = s->streams[wctx->thumbnail.stream_index];
683  tag = av_dict_get(st->metadata, "title", NULL, 0);
684  write_metadata_header(pb, 2, "WM/Picture", attachment_value_size(&wctx->thumbnail, tag));
685 
686  avio_put_str16le(pb, "image/jpeg");
687  avio_w8(pb, 0x10);
688  avio_put_str16le(pb, tag ? tag->value : "");
689 
690  avio_wl32(pb, wctx->thumbnail.size);
691  avio_write(pb, wctx->thumbnail.data, wctx->thumbnail.size);
692 
693  write_tag_int32(pb, "WM/MediaThumbType", 2);
694  }
695 }
696 
698 {
699  WtvContext *wctx = s->priv_data;
700  AVIOContext *pb = s->pb;
701  AVDictionaryEntry *tag = 0;
702  int64_t pos = 0;
703 
704  //FIXME: translate special tags to binary representation
705  while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
706  avio_wl64(pb, pos);
707  pos += metadata_header_size(tag->key) + strlen(tag->value)*2 + 2;
708  }
709 
710  if (wctx->thumbnail.size) {
711  AVStream *st = s->streams[wctx->thumbnail.stream_index];
712  avio_wl64(pb, pos);
713  pos += metadata_header_size("WM/Picture") + attachment_value_size(&wctx->thumbnail, av_dict_get(st->metadata, "title", NULL, 0));
714 
715  avio_wl64(pb, pos);
716  pos += metadata_header_size("WM/MediaThumbType") + 4;
717  }
718 }
719 
720 /**
721  * Pad the remainder of a file
722  * Write out fat table
723  * @return <0 on error
724  */
725 static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos)
726 {
727  WtvContext *wctx = s->priv_data;
728  AVIOContext *pb = s->pb;
729  WtvFile *w = &wctx->file[index];
730  int64_t end_pos = avio_tell(pb);
731  int sector_bits, nb_sectors, pad;
732 
733  av_assert0(index < WTV_FILES);
734 
735  w->length = (end_pos - start_pos);
736 
737  // determine optimal fat table depth, sector_bits, nb_sectors
738  if (w->length <= WTV_SECTOR_SIZE) {
739  w->depth = 0;
740  sector_bits = WTV_SECTOR_BITS;
741  } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
742  w->depth = 1;
743  sector_bits = WTV_SECTOR_BITS;
744  } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
745  w->depth = 1;
746  sector_bits = WTV_BIGSECTOR_BITS;
747  } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
748  w->depth = 2;
749  sector_bits = WTV_SECTOR_BITS;
750  } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
751  w->depth = 2;
752  sector_bits = WTV_BIGSECTOR_BITS;
753  } else {
754  av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (%"PRIi64" bytes)\n", w->length);
755  return -1;
756  }
757 
758  // determine the nb_sectors
759  nb_sectors = (int)(w->length >> sector_bits);
760 
761  // pad sector of timeline
762  pad = (1 << sector_bits) - (w->length % (1 << sector_bits));
763  if (pad) {
764  nb_sectors++;
765  write_pad(pb, pad);
766  }
767 
768  //write fat table
769  if (w->depth > 0) {
770  w->first_sector = write_fat_sector(s, start_pos, nb_sectors, sector_bits, w->depth) >> WTV_SECTOR_BITS;
771  } else {
772  w->first_sector = start_pos >> WTV_SECTOR_BITS;
773  }
774 
775  w->length |= 1ULL<<60;
776  if (sector_bits == WTV_SECTOR_BITS)
777  w->length |= 1ULL<<63;
778 
779  return 0;
780 }
781 
783 {
784  WtvContext *wctx = s->priv_data;
785  AVIOContext *pb = s->pb;
786  int root_size;
787  int64_t sector_pos;
788  int64_t start_pos, file_end_pos;
789 
790  if (finish_file(s, WTV_TIMELINE, wctx->timeline_start_pos) < 0)
791  return -1;
792 
793  start_pos = avio_tell(pb);
795  if (finish_file(s, WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS, start_pos) < 0)
796  return -1;
797 
798  start_pos = avio_tell(pb);
800  if (finish_file(s, WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB, start_pos) < 0)
801  return -1;
802 
803  start_pos = avio_tell(pb);
805  if (finish_file(s, WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB, start_pos) < 0)
806  return -1;
807 
808  start_pos = avio_tell(pb);
810  if (finish_file(s, WTV_TABLE_0_ENTRIES_TIME, start_pos) < 0)
811  return -1;
812 
813  // write root table
814  sector_pos = avio_tell(pb);
815  root_size = write_root_table(s, sector_pos);
816 
817  file_end_pos = avio_tell(pb);
818  // update root value
819  avio_seek(pb, 0x30, SEEK_SET);
820  avio_wl32(pb, root_size);
821  avio_seek(pb, 4, SEEK_CUR);
822  avio_wl32(pb, sector_pos >> WTV_SECTOR_BITS);
823  avio_seek(pb, 0x5c, SEEK_SET);
824  avio_wl32(pb, file_end_pos >> WTV_SECTOR_BITS);
825 
826  avio_flush(pb);
827 
828  av_free(wctx->sp_pairs);
829  av_free(wctx->st_pairs);
830  av_packet_unref(&wctx->thumbnail);
831  return 0;
832 }
833 
835  .name = "wtv",
836  .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
837  .extensions = "wtv",
838  .priv_data_size = sizeof(WtvContext),
839  .audio_codec = AV_CODEC_ID_AC3,
840  .video_codec = AV_CODEC_ID_MPEG2VIDEO,
844  .codec_tag = (const AVCodecTag* const []){ ff_codec_bmp_tags,
845  ff_codec_wav_tags, 0 },
846 };
const uint8_t ff_table_0_entries_time_le16[40]
Definition: wtv_common.c:56
int first_video_flag
Definition: wtvenc.c:98
#define WTV_SECTOR_BITS
Definition: wtv.h:28
const ff_asf_guid ff_metadata_guid
Definition: wtv_common.c:62
#define NULL
Definition: coverity.c:32
#define _
Definition: wtvenc.c:41
static void write_table_entries_time(AVFormatContext *s)
Definition: wtvenc.c:626
const ff_asf_guid ff_SBE2_STREAM_DESC_EVENT
Definition: wtv_common.c:33
void avio_wl16(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:469
Bytestream IO Context.
Definition: avio.h:161
static int shift(int a, int b)
Definition: sonic.c:82
#define WTV_BIGSECTOR_BITS
Definition: wtv.h:30
static int attachment_value_size(const AVPacket *pkt, const AVDictionaryEntry *e)
Definition: wtvenc.c:664
void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par, int for_asf, int ignore_extradata)
Definition: riffenc.c:209
int ff_put_wav_header(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *par, int flags)
Write WAVEFORMAT header structure.
Definition: riffenc.c:54
WtvSyncEntry * st_pairs
Definition: wtvenc.c:100
void ff_put_guid(AVIOContext *s, const ff_asf_guid *g)
Definition: riffenc.c:349
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4882
const char * g
Definition: vf_curves.c:115
static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift)
Definition: wtvenc.c:585
int nb_index
Definition: wtvenc.c:97
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3944
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:943
int num
Numerator.
Definition: rational.h:59
int index
stream index in AVFormatContext
Definition: avformat.h:882
int size
Definition: avcodec.h:1469
const ff_asf_guid * ff_get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid)
Definition: riffenc.c:355
WtvFileIndex
Definition: wtvenc.c:57
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:246
static int64_t write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth)
Definition: wtvenc.c:595
const ff_asf_guid ff_mediatype_video
Definition: wtv_common.c:43
GLint GLenum type
Definition: opengl_enc.c:105
static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id)
Definition: wtvenc.c:158
unsigned int ff_codec_get_tag(const AVCodecTag *tags, enum AVCodecID id)
Definition: utils.c:3114
const char * key
static AVPacket pkt
const void * header
Definition: wtvenc.c:71
int64_t last_timestamp_pos
last timestamp chunk position
Definition: wtvenc.c:93
static int write_table0_header_time(AVIOContext *pb)
Definition: wtvenc.c:519
const ff_asf_guid ff_format_waveformatex
Definition: wtv_common.c:74
This struct describes the properties of an encoded stream.
Definition: avcodec.h:3936
const AVCodecGuid ff_codec_wav_guids[]
Definition: riff.c:594
static int write_root_table(AVFormatContext *s, int64_t sector_pos)
Definition: wtvenc.c:538
Format I/O context.
Definition: avformat.h:1358
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
static void write_table_redirector_legacy_attrib(AVFormatContext *s)
Definition: wtvenc.c:697
const ff_asf_guid ff_data_guid
Definition: wtv_common.c:31
void avio_wl32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:369
uint8_t
#define FF_MEDIASUBTYPE_BASE_GUID
Definition: riff.h:109
static void add_serial_pair(WtvSyncEntry **list, int *count, int64_t serial, int64_t value)
Definition: wtvenc.c:112
int width
Video only.
Definition: avcodec.h:4010
static void put_videoinfoheader2(AVIOContext *pb, AVStream *st)
Definition: wtvenc.c:216
static const uint8_t table_0_redirector_legacy_attrib[]
Definition: wtvenc.c:46
GLsizei GLboolean const GLfloat * value
Definition: opengl_enc.c:109
int64_t length
Definition: wtvdec.c:59
int stream_id
Definition: wtvenc.c:80
const ff_asf_guid ff_mediatype_audio
Definition: wtv_common.c:41
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1426
const ff_asf_guid ff_mediasubtype_cpfilters_processed
Definition: wtv_common.c:68
static const ff_asf_guid sub_wtv_guid
Definition: wtvenc.c:54
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:40
uint8_t * data
Definition: avcodec.h:1468
static int write_stream_codec(AVFormatContext *s, AVStream *st)
Definition: wtvenc.c:317
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
static void finish_chunk_noindex(AVFormatContext *s)
Definition: wtvenc.c:168
static int metadata_header_size(const char *key)
Definition: wtvenc.c:647
uint32_t tag
Definition: movenc.c:1501
ptrdiff_t size
Definition: opengl_enc.c:101
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
Definition: rational.c:35
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:218
const ff_asf_guid ff_sync_guid
Definition: wtv_common.c:37
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:198
#define av_log(a,...)
WTVHeaderWriteFunc * write_header
Definition: wtvenc.c:128
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition: avpacket.c:607
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
Definition: avcodec.h:3973
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1500
void avio_wl64(AVIOContext *s, uint64_t val)
Definition: aviobuf.c:457
WtvChunkEntry index[MAX_NB_INDEX]
Definition: wtvenc.c:96
const uint8_t ff_table_0_entries_legacy_attrib_le16[58]
Definition: wtv_common.c:54
Definition: wtvdec.c:50
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
AVDictionary * metadata
Metadata that applies to the whole file.
Definition: avformat.h:1598
static void write_sync(AVFormatContext *s)
Definition: wtvenc.c:337
int ff_check_h264_startcode(AVFormatContext *s, const AVStream *st, const AVPacket *pkt)
Check presence of H264 startcode.
Definition: mpegtsenc.c:1438
static const uint8_t legacy_attrib[]
Definition: wtvenc.c:50
int WTVHeaderWriteFunc(AVIOContext *pb)
Definition: wtvenc.c:123
static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id)
Write chunk header.
Definition: wtvenc.c:136
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
int64_t timeline_start_pos
Definition: wtvenc.c:89
WtvSyncEntry * sp_pairs
Definition: wtvenc.c:102
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3940
simple assert() macros that are a bit more flexible than ISO C assert().
GLsizei GLsizei * length
Definition: opengl_enc.c:115
#define INDEX_BASE
Definition: wtvenc.c:37
int ff_standardize_creation_time(AVFormatContext *s)
Standardize creation_time metadata in AVFormatContext to an ISO-8601 timestamp string.
Definition: utils.c:5660
int64_t last_pts
Definition: wtvenc.c:105
static void write_index(AVFormatContext *s)
Definition: wtvenc.c:183
GLsizei count
Definition: opengl_enc.c:109
AVRational avg_frame_rate
Average framerate.
Definition: avformat.h:954
const AVCodecTag ff_codec_wav_tags[]
Definition: riff.c:483
const uint8_t ff_timeline_table_0_entries_Events_le16[62]
Definition: wtv_common.c:52
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1474
int extradata_size
Size of the extradata content in bytes.
Definition: avcodec.h:3962
#define write_pad(pb, size)
Definition: wtvenc.c:131
const ff_asf_guid ff_format_cpfilters_processed
Definition: wtv_common.c:72
static const uint8_t table_0_header_time[]
Definition: wtvenc.c:48
const uint8_t * header
Definition: wtvenc.c:126
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1414
static const WTVRootEntryTable wtv_root_entry_table[]
Definition: wtvenc.c:527
int void avio_flush(AVIOContext *s)
Force flushing of buffered data.
Definition: aviobuf.c:238
void ffio_fill(AVIOContext *s, int b, int count)
Definition: aviobuf.c:204
const AVCodecTag ff_codec_bmp_tags[]
Definition: riff.c:32
int depth
Definition: wtvenc.c:72
uint8_t w
Definition: llviddspenc.c:38
static int write_table0_header_legacy_attrib(AVIOContext *pb)
Definition: wtvenc.c:507
const uint8_t ff_timeline_le16[16]
Definition: wtv_common.c:50
#define WTV_PAD8(x)
Definition: wtv.h:31
const char * name
Definition: avformat.h:505
const ff_asf_guid ff_timestamp_guid
Definition: wtv_common.c:29
#define s(width, name)
Definition: cbs_vp9.c:257
static void write_table_entries_attrib(AVFormatContext *s)
Definition: wtvenc.c:669
AVDictionary * metadata
Definition: avformat.h:945
const ff_asf_guid ff_format_mpeg2_video
Definition: wtv_common.c:76
static const uint8_t timeline_table_0_header_events[]
Definition: wtvenc.c:42
preferred ID for MPEG-1/2 video decoding
Definition: avcodec.h:220
static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos)
Pad the remainder of a file Write out fat table.
Definition: wtvenc.c:725
uint8_t ff_asf_guid[16]
Definition: riff.h:90
Stream structure.
Definition: avformat.h:881
static void write_timestamp(AVFormatContext *s, AVPacket *pkt)
Definition: wtvenc.c:442
#define WTV_SECTOR_SIZE
Definition: wtv.h:29
AVIOContext * pb
I/O context.
Definition: avformat.h:1400
int first_sector
Definition: wtvenc.c:73
static int write_stream_codec_info(AVFormatContext *s, AVStream *st)
Definition: wtvenc.c:259
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:196
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:598
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining list
static int write_trailer(AVFormatContext *s)
Definition: wtvenc.c:782
#define MAX_NB_INDEX
Definition: wtvenc.c:38
const ff_asf_guid ff_index_guid
Definition: wtv_common.c:39
int index
Definition: gxfenc.c:89
Rational number (pair of numerator and denominator).
Definition: rational.h:58
static void finish_chunk(AVFormatContext *s)
Definition: wtvenc.c:208
const AVCodecGuid ff_video_guids[]
Definition: wtv_common.c:81
int avio_put_str16le(AVIOContext *s, const char *str)
Convert an UTF-8 string to UTF-16LE and write it.
const AVMetadataConv ff_asf_metadata_conv[]
Definition: asf.c:159
WtvFile file[WTV_FILES]
Definition: wtvenc.c:90
static int write_table0_header_events(AVIOContext *pb)
Definition: wtvenc.c:499
int nb_st_pairs
Definition: wtvenc.c:101
int64_t value
Definition: wtvenc.c:85
AVOutputFormat ff_wtv_muxer
Definition: wtvenc.c:834
int64_t serial
Definition: wtvenc.c:84
static int write_header(AVFormatContext *s)
Definition: wtvenc.c:377
static void write_tag(AVIOContext *pb, const char *key, const char *value)
Definition: wtvenc.c:658
Main libavformat public API header.
int
const ff_asf_guid ff_dir_entry_guid
Definition: wtv_common.c:25
static int write_stream_data(AVFormatContext *s, AVStream *st)
Definition: wtvenc.c:354
#define WTV_BIGSECTOR_SIZE
Definition: wtvenc.c:36
int64_t serial
chunk serial number
Definition: wtvenc.c:91
static const uint8_t table_0_header_legacy_attrib[]
Definition: wtvenc.c:44
char * key
Definition: dict.h:86
int den
Denominator.
Definition: rational.h:60
static int write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: wtvenc.c:460
void ff_metadata_conv(AVDictionary **pm, const AVMetadataConv *d_conv, const AVMetadataConv *s_conv)
Definition: metadata.c:26
const ff_asf_guid ff_format_videoinfo2
Definition: wtv_common.c:78
const ff_asf_guid ff_wtv_guid
Definition: wtv_common.c:27
int64_t last_serial
Definition: wtvenc.c:106
AVPacket thumbnail
Definition: wtvenc.c:108
static void write_table_entries_events(AVFormatContext *s)
Definition: wtvenc.c:615
#define av_free(p)
int64_t last_chunk_pos
last chunk position
Definition: wtvenc.c:92
char * value
Definition: dict.h:87
int64_t first_index_pos
first index_chunk position
Definition: wtvenc.c:94
int len
void * priv_data
Format private data.
Definition: avformat.h:1386
const ff_asf_guid ff_format_none
Definition: wtv_common.c:45
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:3958
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
int64_t serial
Definition: wtvenc.c:78
int nb_sp_pairs
Definition: wtvenc.c:103
#define AV_DICT_IGNORE_SUFFIX
Return first entry in a dictionary whose first part corresponds to the search key, ignoring the suffix of the found key string.
Definition: dict.h:70
static void write_tag_int32(AVIOContext *pb, const char *key, int value)
Definition: wtvenc.c:652
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1028
const ff_asf_guid ff_stream1_guid
Definition: wtv_common.c:35
int64_t pos
Definition: wtvenc.c:77
int stream_index
Definition: avcodec.h:1470
static void write_metadata_header(AVIOContext *pb, int type, const char *key, int value_size)
Definition: wtvenc.c:639
const ff_asf_guid * guid
Definition: wtvenc.c:79
This structure stores compressed data.
Definition: avcodec.h:1445
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1461
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248