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 "internal.h"
32 #include "wtv.h"
33 #include "asf.h"
34 
35 #define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS)
36 #define INDEX_BASE 0x2
37 #define MAX_NB_INDEX 10
38 
39 /* declare utf16le strings */
40 #define _ , 0,
42  {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0};
44  {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
46  {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'r'_'e'_'d'_'i'_'r'_'e'_'c'_'t'_'o'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
47 static const uint8_t table_0_header_time[] =
48  {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'t'_'i'_'m'_'e', 0};
49 static const uint8_t legacy_attrib[] =
50  {'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
51 #undef _
52 
53 static const ff_asf_guid sub_wtv_guid =
54  {0x8C,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
55 
66 };
67 
68 typedef struct {
69  int64_t length;
70  const void *header;
71  int depth;
73 } WtvFile;
74 
75 typedef struct {
76  int64_t pos;
77  int64_t serial;
78  const ff_asf_guid * guid;
79  int stream_id;
81 
82 typedef struct {
83  int64_t serial;
84  int64_t value;
85 } WtvSyncEntry;
86 
87 typedef struct {
90  int64_t serial; /** chunk serial number */
91  int64_t last_chunk_pos; /** last chunk position */
92  int64_t last_timestamp_pos; /** last timestamp chunk position */
93  int64_t first_index_pos; /** first index_chunk position */
94 
96  int nb_index;
98 
99  WtvSyncEntry *st_pairs; /* (serial, timestamp) pairs */
101  WtvSyncEntry *sp_pairs; /* (serial, position) pairs */
103 
104  int64_t last_pts;
105  int64_t last_serial;
106 
108 } WtvContext;
109 
110 
111 static void add_serial_pair(WtvSyncEntry ** list, int * count, int64_t serial, int64_t value)
112 {
113  int new_count = *count + 1;
114  WtvSyncEntry *new_list = av_realloc(*list, new_count * sizeof(WtvSyncEntry));
115  if (!new_list)
116  return;
117  new_list[*count] = (WtvSyncEntry){serial, value};
118  *list = new_list;
119  *count = new_count;
120 }
121 
123 
124 typedef struct {
125  const uint8_t *header;
129 
130 static int write_pad(AVIOContext *pb, int size)
131 {
132  for (; size > 0; size--)
133  avio_w8(pb, 0);
134  return 0;
135 }
136 
137 static const ff_asf_guid *get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid)
138 {
139  int i;
140  for (i = 0; av_guid[i].id != AV_CODEC_ID_NONE; i++) {
141  if (id == av_guid[i].id)
142  return &(av_guid[i].guid);
143  }
144  return NULL;
145 }
146 
147 /**
148  * Write chunk header. If header chunk (0x80000000 set) then add to list of header chunks
149  */
150 static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id)
151 {
152  WtvContext *wctx = s->priv_data;
153  AVIOContext *pb = s->pb;
154 
155  wctx->last_chunk_pos = avio_tell(pb) - wctx->timeline_start_pos;
156  ff_put_guid(pb, guid);
157  avio_wl32(pb, 32 + length);
158  avio_wl32(pb, stream_id);
159  avio_wl64(pb, wctx->serial);
160 
161  if ((stream_id & 0x80000000) && guid != &ff_index_guid) {
162  WtvChunkEntry *t = wctx->index + wctx->nb_index;
164  t->pos = wctx->last_chunk_pos;
165  t->serial = wctx->serial;
166  t->guid = guid;
167  t->stream_id = stream_id & 0x3FFFFFFF;
168  wctx->nb_index++;
169  }
170 }
171 
172 static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id)
173 {
174  WtvContext *wctx = s->priv_data;
175  AVIOContext *pb = s->pb;
176 
177  int64_t last_chunk_pos = wctx->last_chunk_pos;
178  write_chunk_header(s, guid, 0, stream_id); // length updated later
179  avio_wl64(pb, last_chunk_pos);
180 }
181 
183 {
184  WtvContext *wctx = s->priv_data;
185  AVIOContext *pb = s->pb;
186 
187  // update the chunk_len field and pad.
188  int64_t chunk_len = avio_tell(pb) - (wctx->last_chunk_pos + wctx->timeline_start_pos);
189  avio_seek(pb, -(chunk_len - 16), SEEK_CUR);
190  avio_wl32(pb, chunk_len);
191  avio_seek(pb, chunk_len - (16 + 4), SEEK_CUR);
192 
193  write_pad(pb, WTV_PAD8(chunk_len) - chunk_len);
194  wctx->serial++;
195 }
196 
198 {
199  AVIOContext *pb = s->pb;
200  WtvContext *wctx = s->priv_data;
201  int i;
202 
203  write_chunk_header2(s, &ff_index_guid, 0x80000000);
204  avio_wl32(pb, 0);
205  avio_wl32(pb, 0);
206 
207  for (i = 0; i < wctx->nb_index; i++) {
208  WtvChunkEntry *t = wctx->index + i;
209  ff_put_guid(pb, t->guid);
210  avio_wl64(pb, t->pos);
211  avio_wl32(pb, t->stream_id);
212  avio_wl32(pb, 0); // checksum?
213  avio_wl64(pb, t->serial);
214  }
215  wctx->nb_index = 0; // reset index
217 
218  if (!wctx->first_index_pos)
219  wctx->first_index_pos = wctx->last_chunk_pos;
220 }
221 
223 {
224  WtvContext *wctx = s->priv_data;
226  if (wctx->nb_index == MAX_NB_INDEX)
227  write_index(s);
228 }
229 
231 {
232  WtvContext *wctx = s->priv_data;
233  const ff_asf_guid *g, *media_type, *format_type;
234  AVIOContext *pb = s->pb;
235  int64_t hdr_pos_start;
236  int hdr_size = 0;
237 
238  if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
240  media_type = &ff_mediatype_video;
241  format_type = &ff_format_mpeg2_video;
242  } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
244  media_type = &ff_mediatype_audio;
245  format_type = &ff_format_waveformatex;
246  } else {
247  av_log(s, AV_LOG_ERROR, "unknown codec_type (0x%x)\n", st->codec->codec_type);
248  return -1;
249  }
250 
251  if (g == NULL) {
252  av_log(s, AV_LOG_ERROR, "can't get video codec_id (0x%x) guid.\n", st->codec->codec_id);
253  return -1;
254  }
255 
256  ff_put_guid(pb, media_type); // mediatype
258  write_pad(pb, 12);
259  ff_put_guid(pb,&ff_format_cpfilters_processed); // format type
260  avio_wl32(pb, 0); // size
261 
262  hdr_pos_start = avio_tell(pb);
263  if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
264  if (wctx->first_video_flag) {
265  write_pad(pb, 216); //The size is sensitive.
266  wctx->first_video_flag = 0;
267  } else {
268  write_pad(pb, 72); // aspect ratio
270  }
271  } else {
272  ff_put_wav_header(pb, st->codec);
273  }
274  hdr_size = avio_tell(pb) - hdr_pos_start;
275 
276  // seek back write hdr_size
277  avio_seek(pb, -(hdr_size + 4), SEEK_CUR);
278  avio_wl32(pb, hdr_size + 32);
279  avio_seek(pb, hdr_size, SEEK_CUR);
280  ff_put_guid(pb, g); // actual_subtype
281  ff_put_guid(pb, format_type); // actual_formattype
282 
283  return 0;
284 }
285 
287 {
288  AVIOContext *pb = s->pb;
289  int ret;
290  write_chunk_header2(s, &ff_stream1_guid, 0x80000000 | 0x01);
291 
292  avio_wl32(pb, 0x01);
293  write_pad(pb, 4);
294  write_pad(pb, 4);
295 
296  ret = write_stream_codec_info(s, st);
297  if (ret < 0) {
298  av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
299  return -1;
300  }
301 
302  finish_chunk(s);
303  return 0;
304 }
305 
307 {
308  AVIOContext *pb = s->pb;
309  WtvContext *wctx = s->priv_data;
310  int64_t last_chunk_pos = wctx->last_chunk_pos;
311 
312  write_chunk_header(s, &ff_sync_guid, 0x18, 0);
313  avio_wl64(pb, wctx->first_index_pos);
314  avio_wl64(pb, wctx->last_timestamp_pos);
315  avio_wl64(pb, 0);
316 
317  finish_chunk(s);
318  add_serial_pair(&wctx->sp_pairs, &wctx->nb_sp_pairs, wctx->serial, wctx->last_chunk_pos);
319 
320  wctx->last_chunk_pos = last_chunk_pos;
321 }
322 
324 {
325  AVIOContext *pb = s->pb;
326  int ret;
327 
329  avio_wl32(pb, 0x00000001);
330  avio_wl32(pb, st->index + INDEX_BASE); //stream_id
331  avio_wl32(pb, 0x00000001);
332  write_pad(pb, 8);
333 
334  ret = write_stream_codec_info(s, st);
335  if (ret < 0) {
336  av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
337  return -1;
338  }
339  finish_chunk(s);
340 
341  avpriv_set_pts_info(st, 64, 1, 10000000);
342 
343  return 0;
344 }
345 
347 {
348  AVIOContext *pb = s->pb;
349  WtvContext *wctx = s->priv_data;
350  int i, pad, ret;
351  AVStream *st;
352 
353  wctx->last_chunk_pos = -1;
354  wctx->last_timestamp_pos = -1;
355 
356  ff_put_guid(pb, &ff_wtv_guid);
358 
359  avio_wl32(pb, 0x01);
360  avio_wl32(pb, 0x02);
361  avio_wl32(pb, 1 << WTV_SECTOR_BITS);
362  avio_wl32(pb, 1 << WTV_BIGSECTOR_BITS);
363 
364  //write initial root fields
365  avio_wl32(pb, 0); // root_size, update later
366  write_pad(pb, 4);
367  avio_wl32(pb, 0); // root_sector, update it later.
368 
369  write_pad(pb, 32);
370  avio_wl32(pb, 0); // file ends pointer, update it later.
371 
372  pad = (1 << WTV_SECTOR_BITS) - avio_tell(pb);
373  write_pad(pb, pad);
374 
375  wctx->timeline_start_pos = avio_tell(pb);
376 
377  wctx->serial = 1;
378  wctx->last_chunk_pos = -1;
379  wctx->first_video_flag = 1;
380 
381  for (i = 0; i < s->nb_streams; i++) {
382  st = s->streams[i];
383  if (st->codec->codec_id == AV_CODEC_ID_MJPEG)
384  continue;
385  ret = write_stream_codec(s, st);
386  if (ret < 0) {
387  av_log(s, AV_LOG_ERROR, "write stream codec failed codec_type(0x%x)\n", st->codec->codec_type);
388  return -1;
389  }
390  if (!i)
391  write_sync(s);
392  }
393 
394  for (i = 0; i < s->nb_streams; i++) {
395  st = s->streams[i];
396  if (st->codec->codec_id == AV_CODEC_ID_MJPEG)
397  continue;
398  ret = write_stream_data(s, st);
399  if (ret < 0) {
400  av_log(s, AV_LOG_ERROR, "write stream data failed codec_type(0x%x)\n", st->codec->codec_type);
401  return -1;
402  }
403  }
404 
405  if (wctx->nb_index)
406  write_index(s);
407 
408  return 0;
409 }
410 
412 {
413  AVIOContext *pb = s->pb;
414  WtvContext *wctx = s->priv_data;
415  AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
416 
417  write_chunk_header(s, &ff_timestamp_guid, 56, 0x40000000 | (INDEX_BASE + pkt->stream_index));
418  write_pad(pb, 8);
419  avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
420  avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
421  avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
422  avio_wl64(pb, 0);
423  avio_wl64(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO && (pkt->flags & AV_PKT_FLAG_KEY) ? 1 : 0);
424  avio_wl64(pb, 0);
425 
426  wctx->last_timestamp_pos = wctx->last_chunk_pos;
427 }
428 
430 {
431  AVIOContext *pb = s->pb;
432  WtvContext *wctx = s->priv_data;
433 
434  if (s->streams[pkt->stream_index]->codec->codec_id == AV_CODEC_ID_MJPEG && !wctx->thumbnail.size) {
435  av_copy_packet(&wctx->thumbnail, pkt);
436  return 0;
437  }
438 
439  /* emit sync chunk and 'timeline.table.0.entries.Event' record every 50 frames */
440  if (wctx->serial - (wctx->nb_sp_pairs ? wctx->sp_pairs[wctx->nb_sp_pairs - 1].serial : 0) >= 50)
441  write_sync(s);
442 
443  /* emit 'table.0.entries.time' record every 500ms */
444  if (pkt->pts != AV_NOPTS_VALUE && pkt->pts - (wctx->nb_st_pairs ? wctx->st_pairs[wctx->nb_st_pairs - 1].value : 0) >= 5000000)
445  add_serial_pair(&wctx->st_pairs, &wctx->nb_st_pairs, wctx->serial, pkt->pts);
446 
447  if (pkt->pts != AV_NOPTS_VALUE && pkt->pts > wctx->last_pts) {
448  wctx->last_pts = pkt->pts;
449  wctx->last_serial = wctx->serial;
450  }
451 
452  // write timestamp chunk
453  write_timestamp(s, pkt);
454 
456  avio_write(pb, pkt->data, pkt->size);
457  write_pad(pb, WTV_PAD8(pkt->size) - pkt->size);
458 
459  wctx->serial++;
460  return 0;
461 }
462 
464 {
465  avio_wl32(pb, 0x10);
466  write_pad(pb, 84);
467  avio_wl64(pb, 0x32);
468  return 96;
469 }
470 
472 {
473  int pad = 0;
474  avio_wl32(pb, 0xFFFFFFFF);
475  write_pad(pb, 12);
476  avio_write(pb, legacy_attrib, sizeof(legacy_attrib));
477  pad = WTV_PAD8(sizeof(legacy_attrib)) - sizeof(legacy_attrib);
478  write_pad(pb, pad);
479  write_pad(pb, 32);
480  return 48 + WTV_PAD8(sizeof(legacy_attrib));
481 }
482 
484 {
485  avio_wl32(pb, 0x10);
486  write_pad(pb, 76);
487  avio_wl64(pb, 0x40);
488  return 88;
489 }
490 
500 };
501 
502 static int write_root_table(AVFormatContext *s, int64_t sector_pos)
503 {
504  AVIOContext *pb = s->pb;
505  WtvContext *wctx = s->priv_data;
506  int size, pad;
507  int i;
508 
510  for (i = 0; i < sizeof(wtv_root_entry_table)/sizeof(WTVRootEntryTable); i++, h++) {
511  WtvFile *w = &wctx->file[i];
512  int filename_padding = WTV_PAD8(h->header_size) - h->header_size;
513  WTVHeaderWriteFunc *write = h->write_header;
514  int len = 0;
515  int64_t len_pos;
516 
518  len_pos = avio_tell(pb);
519  avio_wl16(pb, 40 + h->header_size + filename_padding + 8); // maybe updated later
520  write_pad(pb, 6);
521  avio_wl64(pb, write ? 0 : w->length);// maybe update later
522  avio_wl32(pb, (h->header_size + filename_padding) >> 1);
523  write_pad(pb, 4);
524 
525  avio_write(pb, h->header, h->header_size);
526  write_pad(pb, filename_padding);
527 
528  if (write) {
529  len = write(pb);
530  // update length field
531  avio_seek(pb, len_pos, SEEK_SET);
532  avio_wl64(pb, 40 + h->header_size + filename_padding + len);
533  avio_wl64(pb, len |(1ULL<<62) | (1ULL<<60));
534  avio_seek(pb, 8 + h->header_size + filename_padding + len, SEEK_CUR);
535  } else {
536  avio_wl32(pb, w->first_sector);
537  avio_wl32(pb, w->depth);
538  }
539  }
540 
541  // caculate root table size
542  size = avio_tell(pb) - sector_pos;
543  pad = WTV_SECTOR_SIZE- size;
544  write_pad(pb, pad);
545 
546  return size;
547 }
548 
549 static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift)
550 {
551  int i;
552  for (i = 0; i < nb_sectors; i++) {
553  avio_wl32(pb, start_sector + (i << shift));
554  }
555  // pad left sector pointer size
556  write_pad(pb, WTV_SECTOR_SIZE - ((nb_sectors << 2) % WTV_SECTOR_SIZE));
557 }
558 
559 static int64_t write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth)
560 {
561  int64_t start_sector = start_pos >> WTV_SECTOR_BITS;
562  int shift = sector_bits - WTV_SECTOR_BITS;
563 
564  int64_t fat = avio_tell(s->pb);
565  write_fat(s->pb, start_sector, nb_sectors, shift);
566 
567  if (depth == 2) {
568  int64_t start_sector1 = fat >> WTV_SECTOR_BITS;
569  int nb_sectors1 = ((nb_sectors << 2) + WTV_SECTOR_SIZE - 1) / WTV_SECTOR_SIZE;
570  int64_t fat1 = avio_tell(s->pb);
571 
572  write_fat(s->pb, start_sector1, nb_sectors1, 0);
573  return fat1;
574  }
575 
576  return fat;
577 }
578 
580 {
581  AVIOContext *pb = s->pb;
582  WtvContext *wctx = s->priv_data;
583  int i;
584  for (i = 0; i < wctx->nb_sp_pairs; i++) {
585  avio_wl64(pb, wctx->sp_pairs[i].serial);
586  avio_wl64(pb, wctx->sp_pairs[i].value);
587  }
588 }
589 
591 {
592  AVIOContext *pb = s->pb;
593  WtvContext *wctx = s->priv_data;
594  int i;
595  for (i = 0; i < wctx->nb_st_pairs; i++) {
596  avio_wl64(pb, wctx->st_pairs[i].value);
597  avio_wl64(pb, wctx->st_pairs[i].serial);
598  }
599  avio_wl64(pb, wctx->last_pts);
600  avio_wl64(pb, wctx->last_serial);
601 }
602 
603 static void write_metadata_header(AVIOContext *pb, int type, const char *key, int value_size)
604 {
606  avio_wl32(pb, type);
607  avio_wl32(pb, value_size);
608  avio_put_str16le(pb, key);
609 }
610 
611 static int metadata_header_size(const char *key)
612 {
613  return 16 + 4 + 4 + strlen(key)*2 + 2;
614 }
615 
616 static void write_tag_int32(AVIOContext *pb, const char *key, int value)
617 {
618  write_metadata_header(pb, 0, key, 4);
619  avio_wl32(pb, value);
620 }
621 
622 static void write_tag(AVIOContext *pb, const char *key, const char *value)
623 {
624  write_metadata_header(pb, 1, key, strlen(value)*2 + 2);
625  avio_put_str16le(pb, value);
626 }
627 
629 {
630  return strlen("image/jpeg")*2 + 2 + 1 + (e ? strlen(e->value)*2 : 0) + 2 + 4 + pkt->size;
631 }
632 
634 {
635  WtvContext *wctx = s->priv_data;
636  AVIOContext *pb = s->pb;
637  AVDictionaryEntry *tag = 0;
638 
639  //FIXME: translate special tags (e.g. WM/Bitrate) to binary representation
641  while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
642  write_tag(pb, tag->key, tag->value);
643 
644  if (wctx->thumbnail.size) {
645  AVStream *st = s->streams[wctx->thumbnail.stream_index];
646  tag = av_dict_get(st->metadata, "title", NULL, 0);
647  write_metadata_header(pb, 2, "WM/Picture", attachment_value_size(&wctx->thumbnail, tag));
648 
649  avio_put_str16le(pb, "image/jpeg");
650  avio_w8(pb, 0x10);
651  avio_put_str16le(pb, tag ? tag->value : "");
652 
653  avio_wl32(pb, wctx->thumbnail.size);
654  avio_write(pb, wctx->thumbnail.data, wctx->thumbnail.size);
655 
656  write_tag_int32(pb, "WM/MediaThumbType", 2);
657  }
658 }
659 
661 {
662  WtvContext *wctx = s->priv_data;
663  AVIOContext *pb = s->pb;
664  AVDictionaryEntry *tag = 0;
665  int64_t pos = 0;
666 
667  //FIXME: translate special tags to binary representation
668  while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
669  avio_wl64(pb, pos);
670  pos += metadata_header_size(tag->key) + strlen(tag->value)*2 + 2;
671  }
672 
673  if (wctx->thumbnail.size) {
674  AVStream *st = s->streams[wctx->thumbnail.stream_index];
675  avio_wl64(pb, pos);
676  pos += metadata_header_size("WM/Picture") + attachment_value_size(&wctx->thumbnail, av_dict_get(st->metadata, "title", NULL, 0));
677 
678  avio_wl64(pb, pos);
679  pos += metadata_header_size("WM/MediaThumbType") + 4;
680  }
681 }
682 
683 /**
684  * Pad the remainder of a file
685  * Write out fat table
686  * @return <0 on error
687  */
688 static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos)
689 {
690  WtvContext *wctx = s->priv_data;
691  AVIOContext *pb = s->pb;
692  WtvFile *w = &wctx->file[index];
693  int64_t end_pos = avio_tell(pb);
694  int sector_bits, nb_sectors, pad;
695 
696  av_assert0(index < WTV_FILES);
697 
698  w->length = (end_pos - start_pos);
699 
700  // determine optimal fat table depth, sector_bits, nb_sectors
701  if (w->length <= WTV_SECTOR_SIZE) {
702  w->depth = 0;
703  sector_bits = WTV_SECTOR_BITS;
704  } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
705  w->depth = 1;
706  sector_bits = WTV_SECTOR_BITS;
707  } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
708  w->depth = 1;
709  sector_bits = WTV_BIGSECTOR_BITS;
710  } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
711  w->depth = 2;
712  sector_bits = WTV_SECTOR_BITS;
713  } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
714  w->depth = 2;
715  sector_bits = WTV_BIGSECTOR_BITS;
716  } else {
717  av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (%"PRIi64" bytes)\n", w->length);
718  return -1;
719  }
720 
721  // determine the nb_sectors
722  nb_sectors = (int)(w->length >> sector_bits);
723 
724  // pad sector of timeline
725  pad = (1 << sector_bits) - (w->length % (1 << sector_bits));
726  if (pad) {
727  nb_sectors++;
728  write_pad(pb, pad);
729  }
730 
731  //write fat table
732  if (w->depth > 0) {
733  w->first_sector = write_fat_sector(s, start_pos, nb_sectors, sector_bits, w->depth) >> WTV_SECTOR_BITS;
734  } else {
735  w->first_sector = start_pos >> WTV_SECTOR_BITS;
736  }
737 
738  w->length |= 1ULL<<60;
739  if (sector_bits == WTV_SECTOR_BITS)
740  w->length |= 1ULL<<63;
741 
742  return 0;
743 }
744 
746 {
747  WtvContext *wctx = s->priv_data;
748  AVIOContext *pb = s->pb;
749  int root_size;
750  int64_t sector_pos;
751  int64_t start_pos, file_end_pos;
752 
753  if (finish_file(s, WTV_TIMELINE, wctx->timeline_start_pos) < 0)
754  return -1;
755 
756  start_pos = avio_tell(pb);
758  if (finish_file(s, WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS, start_pos) < 0)
759  return -1;
760 
761  start_pos = avio_tell(pb);
763  if (finish_file(s, WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB, start_pos) < 0)
764  return -1;
765 
766  start_pos = avio_tell(pb);
768  if (finish_file(s, WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB, start_pos) < 0)
769  return -1;
770 
771  start_pos = avio_tell(pb);
773  if (finish_file(s, WTV_TABLE_0_ENTRIES_TIME, start_pos) < 0)
774  return -1;
775 
776  // write root table
777  sector_pos = avio_tell(pb);
778  root_size = write_root_table(s, sector_pos);
779 
780  file_end_pos = avio_tell(pb);
781  // update root value
782  avio_seek(pb, 0x30, SEEK_SET);
783  avio_wl32(pb, root_size);
784  avio_seek(pb, 4, SEEK_CUR);
785  avio_wl32(pb, sector_pos >> WTV_SECTOR_BITS);
786  avio_seek(pb, 0x5c, SEEK_SET);
787  avio_wl32(pb, file_end_pos >> WTV_SECTOR_BITS);
788 
789  avio_flush(pb);
790 
791  av_free(wctx->sp_pairs);
792  av_free(wctx->st_pairs);
793  av_free_packet(&wctx->thumbnail);
794  return 0;
795 }
796 
798  .name = "wtv",
799  .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
800  .extensions = "wtv",
801  .priv_data_size = sizeof(WtvContext),
802  .audio_codec = AV_CODEC_ID_AC3,
803  .video_codec = AV_CODEC_ID_MPEG2VIDEO,
807  .codec_tag = (const AVCodecTag* const []){ ff_codec_bmp_tags,
808  ff_codec_wav_tags, 0 },
809 };
int first_video_flag
Definition: wtvenc.c:97
#define WTV_SECTOR_BITS
Definition: wtv.h:28
#define _
Definition: wtvenc.c:40
static void write_table_entries_time(AVFormatContext *s)
Definition: wtvenc.c:590
void avio_wl16(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:367
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
static int shift(int a, int b)
Definition: sonic.c:86
#define WTV_BIGSECTOR_BITS
Definition: wtv.h:30
void av_free_packet(AVPacket *pkt)
Free a packet.
Definition: avpacket.c:242
const ff_asf_guid ff_metadata_guid
Definition: wtv.c:62
static int attachment_value_size(const AVPacket *pkt, const AVDictionaryEntry *e)
Definition: wtvenc.c:628
const ff_asf_guid ff_index_guid
Definition: wtv.c:39
const ff_asf_guid ff_wtv_guid
Definition: wtv.c:27
WtvSyncEntry * st_pairs
Definition: wtvenc.c:99
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.
static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift)
Definition: wtvenc.c:549
enum AVCodecID id
Definition: riff.h:76
int nb_index
Definition: wtvenc.c:96
ff_asf_guid guid
Definition: riff.h:77
int index
stream index in AVFormatContext
Definition: avformat.h:644
WtvFileIndex
Definition: wtvenc.c:56
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:199
int av_copy_packet(AVPacket *dst, AVPacket *src)
Copy packet, including contents.
Definition: avpacket.c:236
static int64_t write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth)
Definition: wtvenc.c:559
static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id)
Definition: wtvenc.c:172
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:141
const void * header
Definition: wtvenc.c:70
int64_t last_timestamp_pos
last chunk position
Definition: wtvenc.c:92
AVDictionaryEntry * av_dict_get(AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:39
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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_table0_header_time(AVIOContext *pb)
Definition: wtvenc.c:483
output residual component w
const AVCodecGuid ff_codec_wav_guids[]
Definition: riff.c:394
static int write_root_table(AVFormatContext *s, int64_t sector_pos)
Definition: wtvenc.c:502
Format I/O context.
Definition: avformat.h:944
#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:660
void avio_wl32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:291
uint8_t
static void add_serial_pair(WtvSyncEntry **list, int *count, int64_t serial, int64_t value)
Definition: wtvenc.c:111
static AVPacket pkt
Definition: demuxing.c:56
static const uint8_t table_0_redirector_legacy_attrib[]
Definition: wtvenc.c:45
int64_t length
Definition: wtvdec.c:58
int stream_id
Definition: wtvenc.c:79
AVStream ** streams
Definition: avformat.h:992
const ff_asf_guid ff_dir_entry_guid
Definition: wtv.c:25
static const ff_asf_guid sub_wtv_guid
Definition: wtvenc.c:53
uint8_t * data
static int write_stream_codec(AVFormatContext *s, AVStream *st)
Definition: wtvenc.c:286
static void finish_chunk_noindex(AVFormatContext *s)
Definition: wtvenc.c:182
static int metadata_header_size(const char *key)
Definition: wtvenc.c:611
uint32_t tag
Definition: movenc.c:894
const ff_asf_guid ff_format_waveformatex
Definition: wtv.c:74
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:248
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:173
WTVHeaderWriteFunc * write_header
Definition: wtvenc.c:127
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
void avio_wl64(AVIOContext *s, uint64_t val)
Definition: aviobuf.c:355
WtvChunkEntry index[MAX_NB_INDEX]
first index_chunk position
Definition: wtvenc.c:95
const AVCodecGuid ff_video_guids[]
Definition: wtv.c:79
Definition: wtvdec.c:49
const uint8_t ff_table_0_entries_legacy_attrib_le16[]
Definition: wtv.c:54
AVCodecID
Identify the syntax and semantics of the bitstream.
AVDictionary * metadata
Definition: avformat.h:1092
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
static void write_sync(AVFormatContext *s)
Definition: wtvenc.c:306
static const uint8_t legacy_attrib[]
Definition: wtvenc.c:49
int WTVHeaderWriteFunc(AVIOContext *pb)
Definition: wtvenc.c:122
static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id)
Write chunk header.
Definition: wtvenc.c:150
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
int64_t timeline_start_pos
Definition: wtvenc.c:88
WtvSyncEntry * sp_pairs
Definition: wtvenc.c:101
simple assert() macros that are a bit more flexible than ISO C assert().
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
const ff_asf_guid ff_format_mpeg2_video
Definition: wtv.c:76
#define INDEX_BASE
Definition: wtvenc.c:36
int64_t last_pts
Definition: wtvenc.c:104
static void write_index(AVFormatContext *s)
Definition: wtvenc.c:197
const AVCodecTag ff_codec_wav_tags[]
Definition: riff.c:334
int depth
Definition: v4l.c:62
int size
int flags
A combination of AV_PKT_FLAG values.
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
static const uint8_t table_0_header_time[]
Definition: wtvenc.c:47
const uint8_t * header
Definition: wtvenc.c:125
unsigned int nb_streams
A list of all streams in the file.
Definition: avformat.h:991
static const WTVRootEntryTable wtv_root_entry_table[]
Definition: wtvenc.c:491
FFT buffer for g
Definition: stft_peak.m:17
int void avio_flush(AVIOContext *s)
Force flushing of buffered data to the output s.
Definition: aviobuf.c:193
const ff_asf_guid ff_mediasubtype_cpfilters_processed
Definition: wtv.c:68
const AVCodecTag ff_codec_bmp_tags[]
Definition: riff.c:35
int depth
Definition: wtvenc.c:71
const uint8_t ff_table_0_entries_time_le16[]
Definition: wtv.c:56
ret
Definition: avfilter.c:821
static int write_table0_header_legacy_attrib(AVIOContext *pb)
Definition: wtvenc.c:471
FFmpeg Automated Testing Environment ************************************Table of Contents *****************FFmpeg Automated Testing Environment Introduction Using FATE from your FFmpeg source directory Submitting the results to the FFmpeg result aggregation server FATE makefile targets and variables Makefile targets Makefile variables Examples Introduction **************FATE is an extended regression suite on the client side and a means for results aggregation and presentation on the server side The first part of this document explains how you can use FATE from your FFmpeg source directory to test your ffmpeg binary The second part describes how you can run FATE to submit the results to FFmpeg s FATE server In any way you can have a look at the publicly viewable FATE results by visiting this as it can be seen if some test on some platform broke with their recent contribution This usually happens on the platforms the developers could not test on The second part of this document describes how you can run FATE to submit your results to FFmpeg s FATE server If you want to submit your results be sure to check that your combination of OS and compiler is not already listed on the above mentioned website In the third part you can find a comprehensive listing of FATE makefile targets and variables Using FATE from your FFmpeg source directory **********************************************If you want to run FATE on your machine you need to have the samples in place You can get the samples via the build target fate rsync Use this command from the top level source this will cause FATE to fail NOTE To use a custom wrapper to run the pass target exec to configure or set the TARGET_EXEC Make variable Submitting the results to the FFmpeg result aggregation server ****************************************************************To submit your results to the server you should run fate through the shell script tests fate sh from the FFmpeg sources This script needs to be invoked with a configuration file as its first argument tests fate sh path to fate_config A configuration file template with comments describing the individual configuration variables can be found at doc fate_config sh template Create a configuration that suits your based on the configuration template The slot configuration variable can be any string that is not yet but it is suggested that you name it adhering to the following pattern< arch >< os >< compiler >< compiler version > The configuration file itself will be sourced in a shell therefore all shell features may be used This enables you to setup the environment as you need it for your build For your first test runs the fate_recv variable should be empty or commented out This will run everything as normal except that it will omit the submission of the results to the server The following files should be present in $workdir as specified in the configuration file
Definition: fate.txt:34
const uint8_t ff_timeline_table_0_entries_Events_le16[]
Definition: wtv.c:52
#define WTV_PAD8(x)
Definition: wtv.h:31
t
Definition: genspecsines3.m:6
const char * name
Definition: avformat.h:378
const ff_asf_guid ff_timestamp_guid
Definition: wtv.c:29
static void write_table_entries_attrib(AVFormatContext *s)
Definition: wtvenc.c:633
AVDictionary * metadata
Definition: avformat.h:711
static const uint8_t timeline_table_0_header_events[]
Definition: wtvenc.c:41
preferred ID for MPEG-1/2 video decoding
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:688
const ff_asf_guid ff_SBE2_STREAM_DESC_EVENT
Definition: wtv.c:33
uint8_t ff_asf_guid[16]
Definition: riff.h:59
Stream structure.
Definition: avformat.h:643
static void write_timestamp(AVFormatContext *s, AVPacket *pkt)
Definition: wtvenc.c:411
NULL
Definition: eval.c:55
#define WTV_SECTOR_SIZE
Definition: wtv.h:29
enum AVMediaType codec_type
enum AVCodecID codec_id
const ff_asf_guid ff_stream1_guid
Definition: wtv.c:35
AVIOContext * pb
I/O context.
Definition: avformat.h:977
int first_sector
Definition: wtvenc.c:72
static int write_stream_codec_info(AVFormatContext *s, AVStream *st)
Definition: wtvenc.c:230
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:151
main external API structure.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
static int write_trailer(AVFormatContext *s)
Definition: wtvenc.c:745
#define MAX_NB_INDEX
Definition: wtvenc.c:37
double value
Definition: eval.c:82
const ff_asf_guid ff_data_guid
Definition: wtv.c:31
int index
Definition: gxfenc.c:89
synthesis window for stochastic i
static const ff_asf_guid * get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid)
Definition: wtvenc.c:137
static void finish_chunk(AVFormatContext *s)
Definition: wtvenc.c:222
int avio_put_str16le(AVIOContext *s, const char *str)
Convert an UTF-8 string to UTF-16LE and write it.
Definition: aviobuf.c:318
const AVMetadataConv ff_asf_metadata_conv[]
Definition: asf.c:143
WtvFile file[WTV_FILES]
Definition: wtvenc.c:89
static int write_table0_header_events(AVIOContext *pb)
Definition: wtvenc.c:463
int nb_st_pairs
Definition: wtvenc.c:100
#define type
void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf)
const uint8_t ff_timeline_le16[]
Definition: wtv.c:50
int64_t value
Definition: wtvenc.c:84
AVOutputFormat ff_wtv_muxer
Definition: wtvenc.c:797
const ff_asf_guid ff_format_cpfilters_processed
Definition: wtv.c:72
const ff_asf_guid ff_mediatype_video
Definition: wtv.c:43
int64_t serial
Definition: wtvenc.c:83
static int write_header(AVFormatContext *s)
Definition: wtvenc.c:346
static void write_tag(AVIOContext *pb, const char *key, const char *value)
Definition: wtvenc.c:622
Main libavformat public API header.
static int write_stream_data(AVFormatContext *s, AVStream *st)
Definition: wtvenc.c:323
#define WTV_BIGSECTOR_SIZE
Definition: wtvenc.c:35
int64_t serial
Definition: wtvenc.c:90
int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
static const uint8_t table_0_header_legacy_attrib[]
Definition: wtvenc.c:43
char * key
Definition: dict.h:81
const ff_asf_guid ff_mediatype_audio
Definition: wtv.c:41
static int write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: wtvenc.c:429
void ff_metadata_conv(AVDictionary **pm, const AVMetadataConv *d_conv, const AVMetadataConv *s_conv)
int64_t last_serial
Definition: wtvenc.c:105
AVPacket thumbnail
Definition: wtvenc.c:107
static void write_table_entries_events(AVFormatContext *s)
Definition: wtvenc.c:579
int64_t last_chunk_pos
chunk serial number
Definition: wtvenc.c:91
char * value
Definition: dict.h:82
int64_t first_index_pos
last timestamp chunk position
Definition: wtvenc.c:93
int len
void * priv_data
Format private data.
Definition: avformat.h:964
int64_t serial
Definition: wtvenc.c:77
int nb_sp_pairs
Definition: wtvenc.c:102
static int write_pad(AVIOContext *pb, int size)
Definition: wtvenc.c:130
void INT64 INT64 count
Definition: avisynth_c.h:594
#define AV_DICT_IGNORE_SUFFIX
Definition: dict.h:68
static void write_tag_int32(AVIOContext *pb, const char *key, int value)
Definition: wtvenc.c:616
const char int length
Definition: avisynth_c.h:668
void ff_put_guid(AVIOContext *s, const ff_asf_guid *g)
Definition: asfenc.c:222
int64_t pos
Definition: wtvenc.c:76
const ff_asf_guid ff_sync_guid
Definition: wtv.c:37
static void write_metadata_header(AVIOContext *pb, int type, const char *key, int value_size)
Definition: wtvenc.c:603
const ff_asf_guid * guid
Definition: wtvenc.c:78
This structure stores compressed data.
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:190