FFmpeg
oggdec.c
Go to the documentation of this file.
1 /*
2  * Ogg bitstream support
3  * Luca Barbato <lu_zero@gentoo.org>
4  * Based on tcvp implementation
5  */
6 
7 /*
8  Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
9 
10  Permission is hereby granted, free of charge, to any person
11  obtaining a copy of this software and associated documentation
12  files (the "Software"), to deal in the Software without
13  restriction, including without limitation the rights to use, copy,
14  modify, merge, publish, distribute, sublicense, and/or sell copies
15  of the Software, and to permit persons to whom the Software is
16  furnished to do so, subject to the following conditions:
17 
18  The above copyright notice and this permission notice shall be
19  included in all copies or substantial portions of the Software.
20 
21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  DEALINGS IN THE SOFTWARE.
29  */
30 
31 #include <stdio.h>
32 #include "libavutil/avassert.h"
33 #include "libavutil/intreadwrite.h"
34 #include "avio_internal.h"
35 #include "oggdec.h"
36 #include "avformat.h"
37 #include "internal.h"
38 #include "vorbiscomment.h"
39 
40 #define MAX_PAGE_SIZE 65307
41 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
42 
43 static const struct ogg_codec * const ogg_codecs[] = {
52  &ff_vp8_codec,
59  NULL
60 };
61 
62 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
63 static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
64 static int ogg_restore(AVFormatContext *s);
65 
66 static void free_stream(AVFormatContext *s, int i)
67 {
68  struct ogg *ogg = s->priv_data;
69  struct ogg_stream *stream = &ogg->streams[i];
70 
71  av_freep(&stream->buf);
72  if (stream->codec &&
73  stream->codec->cleanup) {
74  stream->codec->cleanup(s, i);
75  }
76 
77  av_freep(&stream->private);
78  av_freep(&stream->new_metadata);
79 }
80 
81 //FIXME We could avoid some structure duplication
82 static int ogg_save(AVFormatContext *s)
83 {
84  struct ogg *ogg = s->priv_data;
85  struct ogg_state *ost =
86  av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
87  int i;
88  int ret = 0;
89 
90  if (!ost)
91  return AVERROR(ENOMEM);
92 
93  ost->pos = avio_tell(s->pb);
94  ost->curidx = ogg->curidx;
95  ost->next = ogg->state;
96  ost->nstreams = ogg->nstreams;
97  memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
98 
99  for (i = 0; i < ogg->nstreams; i++) {
100  struct ogg_stream *os = ogg->streams + i;
102  if (os->buf)
103  memcpy(os->buf, ost->streams[i].buf, os->bufpos);
104  else
105  ret = AVERROR(ENOMEM);
106  os->new_metadata = NULL;
107  os->new_metadata_size = 0;
108  }
109 
110  ogg->state = ost;
111 
112  if (ret < 0)
113  ogg_restore(s);
114 
115  return ret;
116 }
117 
119 {
120  struct ogg *ogg = s->priv_data;
121  AVIOContext *bc = s->pb;
122  struct ogg_state *ost = ogg->state;
123  int i, err;
124 
125  if (!ost)
126  return 0;
127 
128  ogg->state = ost->next;
129 
130  for (i = 0; i < ogg->nstreams; i++) {
131  struct ogg_stream *stream = &ogg->streams[i];
132  av_freep(&stream->buf);
133  av_freep(&stream->new_metadata);
134 
135  if (i >= ost->nstreams || !ost->streams[i].private) {
136  free_stream(s, i);
137  }
138  }
139 
140  avio_seek(bc, ost->pos, SEEK_SET);
141  ogg->page_pos = -1;
142  ogg->curidx = ost->curidx;
143  ogg->nstreams = ost->nstreams;
144  if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
145  sizeof(*ogg->streams))) < 0) {
146  ogg->nstreams = 0;
147  return err;
148  } else
149  memcpy(ogg->streams, ost->streams,
150  ost->nstreams * sizeof(*ogg->streams));
151 
152  av_free(ost);
153 
154  return 0;
155 }
156 
158 {
159  struct ogg *ogg = s->priv_data;
160  int i;
161  int64_t start_pos = avio_tell(s->pb);
162 
163  for (i = 0; i < ogg->nstreams; i++) {
164  struct ogg_stream *os = ogg->streams + i;
165  os->bufpos = 0;
166  os->pstart = 0;
167  os->psize = 0;
168  os->granule = -1;
169  os->lastpts = AV_NOPTS_VALUE;
170  os->lastdts = AV_NOPTS_VALUE;
171  os->sync_pos = -1;
172  os->page_pos = 0;
173  os->nsegs = 0;
174  os->segp = 0;
175  os->incomplete = 0;
176  os->got_data = 0;
177  if (start_pos <= s->internal->data_offset) {
178  os->lastpts = 0;
179  }
180  os->start_trimming = 0;
181  os->end_trimming = 0;
182  av_freep(&os->new_metadata);
183  os->new_metadata_size = 0;
184  }
185 
186  ogg->page_pos = -1;
187  ogg->curidx = -1;
188 
189  return 0;
190 }
191 
192 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
193 {
194  int i;
195 
196  for (i = 0; ogg_codecs[i]; i++)
197  if (size >= ogg_codecs[i]->magicsize &&
198  !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
199  return ogg_codecs[i];
200 
201  return NULL;
202 }
203 
204 /**
205  * Replace the current stream with a new one. This is a typical webradio
206  * situation where a new audio stream spawn (identified with a new serial) and
207  * must replace the previous one (track switch).
208  */
209 static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic,
210  int probing)
211 {
212  struct ogg *ogg = s->priv_data;
213  struct ogg_stream *os;
214  const struct ogg_codec *codec;
215  int i = 0;
216 
217  if (ogg->nstreams != 1) {
218  avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
219  return AVERROR_PATCHWELCOME;
220  }
221 
222  /* Check for codecs */
223  codec = ogg_find_codec(magic, 8);
224  if (!codec && !probing) {
225  av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
226  return AVERROR_INVALIDDATA;
227  }
228 
229  /* We only have a single stream anyway, so if there's a new stream with
230  * a different codec just replace it */
231  os = &ogg->streams[0];
232  os->serial = serial;
233  os->codec = codec;
234  os->serial = serial;
235  os->lastpts = 0;
236  os->lastdts = 0;
237  os->start_trimming = 0;
238  os->end_trimming = 0;
239 
240  /* Chained files have extradata as a new packet */
241  if (codec == &ff_opus_codec)
242  os->header = -1;
243 
244  return i;
245 }
246 
247 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
248 {
249  struct ogg *ogg = s->priv_data;
250  int idx = ogg->nstreams;
251  AVStream *st;
252  struct ogg_stream *os;
253  size_t size;
254 
255  if (ogg->state) {
256  av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
257  "in between Ogg context save/restore operations.\n");
258  return AVERROR_BUG;
259  }
260 
261  /* Allocate and init a new Ogg Stream */
262  if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
263  !(os = av_realloc(ogg->streams, size)))
264  return AVERROR(ENOMEM);
265  ogg->streams = os;
266  os = ogg->streams + idx;
267  memset(os, 0, sizeof(*os));
268  os->serial = serial;
271  os->header = -1;
273  if (!os->buf)
274  return AVERROR(ENOMEM);
275 
276  /* Create the associated AVStream */
277  st = avformat_new_stream(s, NULL);
278  if (!st) {
279  av_freep(&os->buf);
280  return AVERROR(ENOMEM);
281  }
282  st->id = idx;
283  avpriv_set_pts_info(st, 64, 1, 1000000);
284 
285  ogg->nstreams++;
286  return idx;
287 }
288 
289 static int data_packets_seen(const struct ogg *ogg)
290 {
291  int i;
292 
293  for (i = 0; i < ogg->nstreams; i++)
294  if (ogg->streams[i].got_data)
295  return 1;
296  return 0;
297 }
298 
299 static int buf_realloc(struct ogg_stream *os, int size)
300 {
301  /* Even if invalid guarantee there's enough memory to read the page */
302  if (os->bufsize - os->bufpos < size) {
304  if (!nb)
305  return AVERROR(ENOMEM);
306  os->buf = nb;
307  os->bufsize *= 2;
308  }
309 
310  return 0;
311 }
312 
313 static int ogg_read_page(AVFormatContext *s, int *sid, int probing)
314 {
315  AVIOContext *bc = s->pb;
316  struct ogg *ogg = s->priv_data;
317  struct ogg_stream *os;
318  int ret, i = 0;
319  int flags, nsegs;
320  uint64_t gp;
321  uint32_t serial;
322  uint32_t crc, crc_tmp;
323  int size = 0, idx;
324  int64_t version, page_pos;
325  int64_t start_pos;
326  uint8_t sync[4];
327  uint8_t segments[255];
328  uint8_t *readout_buf;
329  int sp = 0;
330 
331  ret = avio_read(bc, sync, 4);
332  if (ret < 4)
333  return ret < 0 ? ret : AVERROR_EOF;
334 
335  do {
336  int c;
337 
338  if (sync[sp & 3] == 'O' &&
339  sync[(sp + 1) & 3] == 'g' &&
340  sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
341  break;
342 
343  if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
344  memset(sync, 0, 4);
345  avio_seek(bc, ogg->page_pos+4, SEEK_SET);
346  ogg->page_pos = -1;
347  }
348 
349  c = avio_r8(bc);
350 
351  if (avio_feof(bc))
352  return AVERROR_EOF;
353 
354  sync[sp++ & 3] = c;
355  } while (i++ < MAX_PAGE_SIZE);
356 
357  if (i >= MAX_PAGE_SIZE) {
358  av_log(s, AV_LOG_INFO, "cannot find sync word\n");
359  return AVERROR_INVALIDDATA;
360  }
361 
362  /* 0x4fa9b05f = av_crc(AV_CRC_32_IEEE, 0x0, "OggS", 4) */
363  ffio_init_checksum(bc, ff_crc04C11DB7_update, 0x4fa9b05f);
364 
365  /* To rewind if checksum is bad/check magic on switches - this is the max packet size */
367  start_pos = avio_tell(bc);
368 
369  version = avio_r8(bc);
370  flags = avio_r8(bc);
371  gp = avio_rl64(bc);
372  serial = avio_rl32(bc);
373  avio_skip(bc, 4); /* seq */
374 
375  crc_tmp = ffio_get_checksum(bc);
376  crc = avio_rb32(bc);
377  crc_tmp = ff_crc04C11DB7_update(crc_tmp, (uint8_t[4]){0}, 4);
379 
380  nsegs = avio_r8(bc);
381  page_pos = avio_tell(bc) - 27;
382 
383  ret = avio_read(bc, segments, nsegs);
384  if (ret < nsegs)
385  return ret < 0 ? ret : AVERROR_EOF;
386 
387  for (i = 0; i < nsegs; i++)
388  size += segments[i];
389 
390  idx = ogg_find_stream(ogg, serial);
391  if (idx >= 0) {
392  os = ogg->streams + idx;
393 
394  ret = buf_realloc(os, size);
395  if (ret < 0)
396  return ret;
397 
398  readout_buf = os->buf + os->bufpos;
399  } else {
400  readout_buf = av_malloc(size);
401  }
402 
403  ret = avio_read(bc, readout_buf, size);
404  if (ret < size) {
405  if (idx < 0)
406  av_free(readout_buf);
407  return ret < 0 ? ret : AVERROR_EOF;
408  }
409 
410  if (crc ^ ffio_get_checksum(bc)) {
411  av_log(s, AV_LOG_ERROR, "CRC mismatch!\n");
412  if (idx < 0)
413  av_free(readout_buf);
414  avio_seek(bc, start_pos, SEEK_SET);
415  return 0;
416  }
417 
418  /* Since we're almost sure its a valid packet, checking the version after
419  * the checksum lets the demuxer be more tolerant */
420  if (version) {
421  av_log(s, AV_LOG_ERROR, "Invalid Ogg vers!\n");
422  if (idx < 0)
423  av_free(readout_buf);
424  avio_seek(bc, start_pos, SEEK_SET);
425  return 0;
426  }
427 
428  /* CRC is correct so we can be 99% sure there's an actual change here */
429  if (idx < 0) {
430  if (data_packets_seen(ogg))
431  idx = ogg_replace_stream(s, serial, readout_buf, probing);
432  else
433  idx = ogg_new_stream(s, serial);
434 
435  if (idx < 0) {
436  av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
437  av_free(readout_buf);
438  return idx;
439  }
440 
441  os = ogg->streams + idx;
442 
443  ret = buf_realloc(os, size);
444  if (ret < 0) {
445  av_free(readout_buf);
446  return ret;
447  }
448 
449  memcpy(os->buf + os->bufpos, readout_buf, size);
450  av_free(readout_buf);
451  }
452 
453  ogg->page_pos = page_pos;
454  os->page_pos = page_pos;
455  os->nsegs = nsegs;
456  os->segp = 0;
457  os->got_data = !(flags & OGG_FLAG_BOS);
458  os->bufpos += size;
459  os->granule = gp;
460  os->flags = flags;
461  memcpy(os->segments, segments, nsegs);
462  memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
463 
464  if (flags & OGG_FLAG_CONT || os->incomplete) {
465  if (!os->psize) {
466  // If this is the very first segment we started
467  // playback in the middle of a continuation packet.
468  // Discard it since we missed the start of it.
469  while (os->segp < os->nsegs) {
470  int seg = os->segments[os->segp++];
471  os->pstart += seg;
472  if (seg < 255)
473  break;
474  }
475  os->sync_pos = os->page_pos;
476  }
477  } else {
478  os->psize = 0;
479  os->sync_pos = os->page_pos;
480  }
481 
482  /* This function is always called with sid != NULL */
483  *sid = idx;
484 
485  return 0;
486 }
487 
488 /**
489  * @brief find the next Ogg packet
490  * @param *sid is set to the stream for the packet or -1 if there is
491  * no matching stream, in that case assume all other return
492  * values to be uninitialized.
493  * @return negative value on error or EOF.
494  */
495 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
496  int64_t *fpos)
497 {
498  struct ogg *ogg = s->priv_data;
499  int idx, i, ret;
500  struct ogg_stream *os;
501  int complete = 0;
502  int segp = 0, psize = 0;
503 
504  av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
505  if (sid)
506  *sid = -1;
507 
508  do {
509  idx = ogg->curidx;
510 
511  while (idx < 0) {
512  ret = ogg_read_page(s, &idx, 0);
513  if (ret < 0)
514  return ret;
515  }
516 
517  os = ogg->streams + idx;
518 
519  av_log(s, AV_LOG_TRACE, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
520  idx, os->pstart, os->psize, os->segp, os->nsegs);
521 
522  if (!os->codec) {
523  if (os->header < 0) {
524  os->codec = ogg_find_codec(os->buf, os->bufpos);
525  if (!os->codec) {
526  av_log(s, AV_LOG_WARNING, "Codec not found\n");
527  os->header = 0;
528  return 0;
529  }
530  } else {
531  return 0;
532  }
533  }
534 
535  segp = os->segp;
536  psize = os->psize;
537 
538  while (os->segp < os->nsegs) {
539  int ss = os->segments[os->segp++];
540  os->psize += ss;
541  if (ss < 255) {
542  complete = 1;
543  break;
544  }
545  }
546 
547  if (!complete && os->segp == os->nsegs) {
548  ogg->curidx = -1;
549  // Do not set incomplete for empty packets.
550  // Together with the code in ogg_read_page
551  // that discards all continuation of empty packets
552  // we would get an infinite loop.
553  os->incomplete = !!os->psize;
554  }
555  } while (!complete);
556 
557 
558  if (os->granule == -1)
560  "Page at %"PRId64" is missing granule\n",
561  os->page_pos);
562 
563  ogg->curidx = idx;
564  os->incomplete = 0;
565 
566  if (os->header) {
567  if ((ret = os->codec->header(s, idx)) < 0) {
568  av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret));
569  return ret;
570  }
571  os->header = ret;
572  if (!os->header) {
573  os->segp = segp;
574  os->psize = psize;
575 
576  // We have reached the first non-header packet in this stream.
577  // Unfortunately more header packets may still follow for others,
578  // but if we continue with header parsing we may lose data packets.
579  ogg->headers = 1;
580 
581  // Update the header state for all streams and
582  // compute the data_offset.
583  if (!s->internal->data_offset)
584  s->internal->data_offset = os->sync_pos;
585 
586  for (i = 0; i < ogg->nstreams; i++) {
587  struct ogg_stream *cur_os = ogg->streams + i;
588 
589  // if we have a partial non-header packet, its start is
590  // obviously at or after the data start
591  if (cur_os->incomplete)
593  }
594  } else {
595  os->nb_header++;
596  os->pstart += os->psize;
597  os->psize = 0;
598  }
599  } else {
600  os->pflags = 0;
601  os->pduration = 0;
602  if (os->codec && os->codec->packet) {
603  if ((ret = os->codec->packet(s, idx)) < 0) {
604  av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret));
605  return ret;
606  }
607  }
608  if (sid)
609  *sid = idx;
610  if (dstart)
611  *dstart = os->pstart;
612  if (dsize)
613  *dsize = os->psize;
614  if (fpos)
615  *fpos = os->sync_pos;
616  os->pstart += os->psize;
617  os->psize = 0;
618  if(os->pstart == os->bufpos)
619  os->bufpos = os->pstart = 0;
620  os->sync_pos = os->page_pos;
621  }
622 
623  // determine whether there are more complete packets in this page
624  // if not, the page's granule will apply to this packet
625  os->page_end = 1;
626  for (i = os->segp; i < os->nsegs; i++)
627  if (os->segments[i] < 255) {
628  os->page_end = 0;
629  break;
630  }
631 
632  if (os->segp == os->nsegs)
633  ogg->curidx = -1;
634 
635  return 0;
636 }
637 
639 {
640  struct ogg *ogg = s->priv_data;
641  int i, ret;
642  int64_t size, end;
643  int streams_left=0;
644 
645  if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
646  return 0;
647 
648 // already set
649  if (s->duration != AV_NOPTS_VALUE)
650  return 0;
651 
652  size = avio_size(s->pb);
653  if (size < 0)
654  return 0;
655  end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
656 
657  ret = ogg_save(s);
658  if (ret < 0)
659  return ret;
660  avio_seek(s->pb, end, SEEK_SET);
661  ogg->page_pos = -1;
662 
663  while (!ogg_read_page(s, &i, 1)) {
664  if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
665  ogg->streams[i].codec) {
666  s->streams[i]->duration =
667  ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
668  if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
669  s->streams[i]->duration -= s->streams[i]->start_time;
670  streams_left-= (ogg->streams[i].got_start==-1);
671  ogg->streams[i].got_start= 1;
672  } else if(!ogg->streams[i].got_start) {
673  ogg->streams[i].got_start= -1;
674  streams_left++;
675  }
676  }
677  }
678 
679  ogg_restore(s);
680 
681  ret = ogg_save(s);
682  if (ret < 0)
683  return ret;
684 
685  avio_seek (s->pb, s->internal->data_offset, SEEK_SET);
686  ogg_reset(s);
687  while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
688  int64_t pts;
689  if (i < 0) continue;
690  pts = ogg_calc_pts(s, i, NULL);
691  if (s->streams[i]->duration == AV_NOPTS_VALUE)
692  continue;
693  if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
694  s->streams[i]->duration -= pts;
695  ogg->streams[i].got_start= 1;
696  streams_left--;
697  }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
698  ogg->streams[i].got_start= 1;
699  streams_left--;
700  }
701  }
702  ogg_restore (s);
703 
704  return 0;
705 }
706 
708 {
709  struct ogg *ogg = s->priv_data;
710  int i;
711 
712  for (i = 0; i < ogg->nstreams; i++) {
713  free_stream(s, i);
714  }
715 
716  ogg->nstreams = 0;
717 
718  av_freep(&ogg->streams);
719  return 0;
720 }
721 
723 {
724  struct ogg *ogg = s->priv_data;
725  int ret, i;
726 
727  ogg->curidx = -1;
728 
729  //linear headers seek from start
730  do {
731  ret = ogg_packet(s, NULL, NULL, NULL, NULL);
732  if (ret < 0) {
733  ogg_read_close(s);
734  return ret;
735  }
736  } while (!ogg->headers);
737  av_log(s, AV_LOG_TRACE, "found headers\n");
738 
739  for (i = 0; i < ogg->nstreams; i++) {
740  struct ogg_stream *os = ogg->streams + i;
741 
742  if (ogg->streams[i].header < 0) {
743  av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
744  ogg->streams[i].codec = NULL;
745  av_freep(&ogg->streams[i].private);
746  } else if (os->codec && os->nb_header < os->codec->nb_header) {
748  "Headers mismatch for stream %d: "
749  "expected %d received %d.\n",
750  i, os->codec->nb_header, os->nb_header);
751  if (s->error_recognition & AV_EF_EXPLODE) {
752  ogg_read_close(s);
753  return AVERROR_INVALIDDATA;
754  }
755  }
757  os->lastpts = s->streams[i]->start_time =
758  ogg_gptopts(s, i, os->start_granule, NULL);
759  }
760 
761  //linear granulepos seek from end
762  ret = ogg_get_length(s);
763  if (ret < 0) {
764  ogg_read_close(s);
765  return ret;
766  }
767 
768  return 0;
769 }
770 
771 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
772 {
773  struct ogg *ogg = s->priv_data;
774  struct ogg_stream *os = ogg->streams + idx;
775  int64_t pts = AV_NOPTS_VALUE;
776 
777  if (dts)
778  *dts = AV_NOPTS_VALUE;
779 
780  if (os->lastpts != AV_NOPTS_VALUE) {
781  pts = os->lastpts;
782  os->lastpts = AV_NOPTS_VALUE;
783  }
784  if (os->lastdts != AV_NOPTS_VALUE) {
785  if (dts)
786  *dts = os->lastdts;
787  os->lastdts = AV_NOPTS_VALUE;
788  }
789  if (os->page_end) {
790  if (os->granule != -1LL) {
791  if (os->codec && os->codec->granule_is_start)
792  pts = ogg_gptopts(s, idx, os->granule, dts);
793  else
794  os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
795  os->granule = -1LL;
796  }
797  }
798  return pts;
799 }
800 
801 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
802 {
803  struct ogg *ogg = s->priv_data;
804  struct ogg_stream *os = ogg->streams + idx;
805  int invalid = 0;
806  if (psize) {
807  switch (s->streams[idx]->codecpar->codec_id) {
808  case AV_CODEC_ID_THEORA:
809  invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
810  break;
811  case AV_CODEC_ID_VP8:
812  invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
813  }
814  if (invalid) {
815  os->pflags ^= AV_PKT_FLAG_KEY;
816  av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
817  (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
818  }
819  }
820 }
821 
823 {
824  struct ogg *ogg;
825  struct ogg_stream *os;
826  int idx, ret;
827  int pstart, psize;
828  int64_t fpos, pts, dts;
829 
830  if (s->io_repositioned) {
831  ogg_reset(s);
832  s->io_repositioned = 0;
833  }
834 
835  //Get an ogg packet
836 retry:
837  do {
838  ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
839  if (ret < 0)
840  return ret;
841  } while (idx < 0 || !s->streams[idx]);
842 
843  ogg = s->priv_data;
844  os = ogg->streams + idx;
845 
846  // pflags might not be set until after this
847  pts = ogg_calc_pts(s, idx, &dts);
848  ogg_validate_keyframe(s, idx, pstart, psize);
849 
850  if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
851  goto retry;
852  os->keyframe_seek = 0;
853 
854  //Alloc a pkt
855  ret = av_new_packet(pkt, psize);
856  if (ret < 0)
857  return ret;
858  pkt->stream_index = idx;
859  memcpy(pkt->data, os->buf + pstart, psize);
860 
861  pkt->pts = pts;
862  pkt->dts = dts;
863  pkt->flags = os->pflags;
864  pkt->duration = os->pduration;
865  pkt->pos = fpos;
866 
867  if (os->start_trimming || os->end_trimming) {
868  uint8_t *side_data = av_packet_new_side_data(pkt,
870  10);
871  if(!side_data)
872  return AVERROR(ENOMEM);
873  AV_WL32(side_data + 0, os->start_trimming);
874  AV_WL32(side_data + 4, os->end_trimming);
875  os->start_trimming = 0;
876  os->end_trimming = 0;
877  }
878 
879  if (os->new_metadata) {
882  if (ret < 0)
883  return ret;
884 
885  os->new_metadata = NULL;
886  os->new_metadata_size = 0;
887  }
888 
889  return psize;
890 }
891 
892 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
893  int64_t *pos_arg, int64_t pos_limit)
894 {
895  struct ogg *ogg = s->priv_data;
896  AVIOContext *bc = s->pb;
897  int64_t pts = AV_NOPTS_VALUE;
898  int64_t keypos = -1;
899  int i;
900  int pstart, psize;
901  avio_seek(bc, *pos_arg, SEEK_SET);
902  ogg_reset(s);
903 
904  while ( avio_tell(bc) <= pos_limit
905  && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
906  if (i == stream_index) {
907  struct ogg_stream *os = ogg->streams + stream_index;
908  // Do not trust the last timestamps of an ogm video
909  if ( (os->flags & OGG_FLAG_EOS)
910  && !(os->flags & OGG_FLAG_BOS)
911  && os->codec == &ff_ogm_video_codec)
912  continue;
913  pts = ogg_calc_pts(s, i, NULL);
914  ogg_validate_keyframe(s, i, pstart, psize);
915  if (os->pflags & AV_PKT_FLAG_KEY) {
916  keypos = *pos_arg;
917  } else if (os->keyframe_seek) {
918  // if we had a previous keyframe but no pts for it,
919  // return that keyframe with this pts value.
920  if (keypos >= 0)
921  *pos_arg = keypos;
922  else
923  pts = AV_NOPTS_VALUE;
924  }
925  }
926  if (pts != AV_NOPTS_VALUE)
927  break;
928  }
929  ogg_reset(s);
930  return pts;
931 }
932 
933 static int ogg_read_seek(AVFormatContext *s, int stream_index,
934  int64_t timestamp, int flags)
935 {
936  struct ogg *ogg = s->priv_data;
937  struct ogg_stream *os = ogg->streams + stream_index;
938  int ret;
939 
940  av_assert0(stream_index < ogg->nstreams);
941  // Ensure everything is reset even when seeking via
942  // the generated index.
943  ogg_reset(s);
944 
945  // Try seeking to a keyframe first. If this fails (very possible),
946  // av_seek_frame will fall back to ignoring keyframes
947  if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
948  && !(flags & AVSEEK_FLAG_ANY))
949  os->keyframe_seek = 1;
950 
951  ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
952  ogg_reset(s);
953  os = ogg->streams + stream_index;
954  if (ret < 0)
955  os->keyframe_seek = 0;
956  return ret;
957 }
958 
959 static int ogg_probe(const AVProbeData *p)
960 {
961  if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
962  return AVPROBE_SCORE_MAX;
963  return 0;
964 }
965 
967  .name = "ogg",
968  .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
969  .priv_data_size = sizeof(struct ogg),
970  .read_probe = ogg_probe,
971  .read_header = ogg_read_header,
972  .read_packet = ogg_read_packet,
973  .read_close = ogg_read_close,
974  .read_seek = ogg_read_seek,
975  .read_timestamp = ogg_read_timestamp,
976  .extensions = "ogg",
978 };
int headers
Definition: oggdec.h:105
int header
Definition: oggdec.h:78
int granule_is_start
1 if granule is the start time of the associated packet.
Definition: oggdec.h:53
#define NULL
Definition: coverity.c:32
#define AVFMT_NOBINSEARCH
Format does not allow to fall back on binary search via read_timestamp.
Definition: avformat.h:468
Bytestream IO Context.
Definition: avio.h:161
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:334
version
Definition: libkvazaar.c:292
A list of zero terminated key/value strings.
Definition: packet.h:209
int nstreams
Definition: oggdec.h:104
Copyright (C) 2005 Michael Ahlberg, Måns Rullgård.
Definition: oggdec.h:31
static const struct ogg_codec * ogg_find_codec(uint8_t *buf, int size)
Definition: oggdec.c:192
unsigned int bufsize
Definition: oggdec.h:63
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:134
unsigned int pflags
Definition: oggdec.h:67
const struct ogg_codec ff_celt_codec
Definition: oggparsecelt.c:92
#define DECODER_BUFFER_SIZE
Definition: oggdec.c:41
int nb_header
set to the number of parsed headers
Definition: oggdec.h:86
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
int(* packet)(AVFormatContext *, int)
Definition: oggdec.h:42
int64_t pos
byte position in stream, -1 if unknown
Definition: packet.h:375
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:4938
#define OGG_NOGRANULE_VALUE
Definition: oggdec.h:115
#define AVSEEK_FLAG_ANY
seek to any frame, even non-keyframes
Definition: avformat.h:2514
const struct ogg_codec * codec
Definition: oggdec.h:77
int64_t data_offset
offset of the first packet
Definition: internal.h:80
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:241
AVFormatInternal * internal
An opaque field for libavformat internal usage.
Definition: avformat.h:1804
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:329
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
int flags
Definition: oggdec.h:76
#define OGG_FLAG_CONT
Definition: oggdec.h:111
static AVPacket pkt
static int ogg_get_length(AVFormatContext *s)
Definition: oggdec.c:638
static const struct ogg_codec *const ogg_codecs[]
Definition: oggdec.c:43
static int ogg_restore(AVFormatContext *s)
Definition: oggdec.c:118
int64_t lastpts
Definition: oggdec.h:72
static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: oggdec.c:822
const struct ogg_codec ff_ogm_old_codec
Definition: oggparseogm.c:221
Format I/O context.
Definition: avformat.h:1351
static int buf_realloc(struct ogg_stream *os, int size)
Definition: oggdec.c:299
unsigned int psize
Definition: oggdec.h:66
int64_t sync_pos
file offset of the first page needed to reconstruct the current packet
Definition: oggdec.h:74
uint64_t pos
Definition: oggdec.h:95
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
uint8_t
#define av_malloc(s)
const struct ogg_codec ff_ogm_video_codec
Definition: oggparseogm.c:194
static int data_packets_seen(const struct ogg *ogg)
Definition: oggdec.c:289
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:202
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:778
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:373
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
int id
Format-specific stream ID.
Definition: avformat.h:883
int(* header)(AVFormatContext *, int)
Attempt to process a packet as a header.
Definition: oggdec.h:41
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4519
int64_t page_pos
file offset of the current page
Definition: oggdec.h:75
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1419
struct ogg_state * state
Definition: oggdec.h:108
uint8_t * data
Definition: packet.h:355
int nstreams
Definition: oggdec.h:98
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define sp
Definition: regdef.h:63
int start_trimming
set the number of packets to drop from the start
Definition: oggdec.h:87
int end_trimming
set the number of packets to drop from the end
Definition: oggdec.h:88
ptrdiff_t size
Definition: opengl_enc.c:100
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Definition: oggdec.c:933
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:625
const struct ogg_codec ff_skeleton_codec
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:388
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:87
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
static int ogg_read_page(AVFormatContext *s, int *sid, int probing)
Definition: oggdec.c:313
#define AVFMT_TS_DISCONT
Format allows timestamp discontinuities.
Definition: avformat.h:464
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:747
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
static int ogg_read_close(AVFormatContext *s)
Definition: oggdec.c:707
#define MAX_PAGE_SIZE
Definition: oggdec.c:40
#define OGG_FLAG_EOS
Definition: oggdec.h:113
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
simple assert() macros that are a bit more flexible than ISO C assert().
static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic, int probing)
Replace the current stream with a new one.
Definition: oggdec.c:209
const struct ogg_codec ff_opus_codec
Definition: oggparseopus.c:181
uint8_t segments[255]
Definition: oggdec.h:80
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:361
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:616
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
Allocate, reallocate, or free an array through a pointer to a pointer.
Definition: mem.c:206
int incomplete
whether we&#39;re expecting a continuation in the next page
Definition: oggdec.h:81
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:443
void ffio_init_checksum(AVIOContext *s, unsigned long(*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum)
Definition: aviobuf.c:604
#define ss(width, name, subs,...)
Definition: cbs_vp9.c:261
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:260
uint32_t serial
Definition: oggdec.h:69
#define FFMIN(a, b)
Definition: common.h:96
unsigned int new_metadata_size
Definition: oggdec.h:90
uint64_t granule
Definition: oggdec.h:70
unsigned int pstart
Definition: oggdec.h:65
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
Definition: oggdec.c:771
uint64_t start_granule
Definition: oggdec.h:71
unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, unsigned int len)
Definition: aviobuf.c:578
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
struct ogg_stream * streams
Definition: oggdec.h:103
int segp
Definition: oggdec.h:79
const struct ogg_codec ff_vorbis_codec
#define OGG_FLAG_BOS
Definition: oggdec.h:112
const struct ogg_codec ff_vp8_codec
Definition: oggparsevp8.c:139
#define s(width, name)
Definition: cbs_vp9.c:257
int page_end
current packet is the last one completed in the page
Definition: oggdec.h:82
AVInputFormat ff_ogg_demuxer
Definition: oggdec.c:966
#define AV_EF_EXPLODE
abort decoding on minor error detection
Definition: avcodec.h:1666
const struct ogg_codec ff_ogm_audio_codec
Definition: oggparseogm.c:203
Stream structure.
Definition: avformat.h:876
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
const struct ogg_codec ff_theora_codec
#define AVIO_SEEKABLE_NORMAL
Seeking works like for a local file.
Definition: avio.h:40
static int ogg_find_stream(struct ogg *ogg, int serial)
Definition: oggdec.h:140
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
unsigned int pduration
Definition: oggdec.h:68
static int ogg_probe(const AVProbeData *p)
Definition: oggdec.c:959
int got_start
Definition: oggdec.h:84
int nsegs
Definition: oggdec.h:79
AVIOContext * pb
I/O context.
Definition: avformat.h:1393
static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize, int64_t *fpos)
find the next Ogg packet
Definition: oggdec.c:495
const struct ogg_codec ff_flac_codec
Definition: oggparseflac.c:128
const struct ogg_codec ff_old_dirac_codec
int io_repositioned
IO repositioned flag.
Definition: avformat.h:1812
void * private
Definition: oggdec.h:91
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
#define AVFMT_GENERIC_INDEX
Use generic index building code.
Definition: avformat.h:463
struct ogg_state * next
Definition: oggdec.h:97
uint8_t * new_metadata
Definition: oggdec.h:89
static int ogg_read_header(AVFormatContext *s)
Definition: oggdec.c:722
int nb_header
Number of expected headers.
Definition: oggdec.h:57
Recommmends skipping the specified number of samples.
Definition: packet.h:156
FF_ENABLE_DEPRECATION_WARNINGS int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type, uint8_t *data, size_t size)
Wrap an existing array as a packet side data.
Definition: avpacket.c:297
unsigned long ffio_get_checksum(AVIOContext *s)
Definition: aviobuf.c:596
static int ogg_reset(AVFormatContext *s)
Definition: oggdec.c:157
int64_t lastdts
Definition: oggdec.h:73
This structure contains the data a format has to probe a file.
Definition: avformat.h:441
const struct ogg_codec ff_old_flac_codec
Definition: oggparseflac.c:135
void(* cleanup)(AVFormatContext *s, int idx)
Definition: oggdec.h:58
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
static int64_t pts
#define flags(name, subs,...)
Definition: cbs_av1.c:564
int curidx
Definition: oggdec.h:96
const int8_t * magic
Definition: oggdec.h:32
const struct ogg_codec ff_dirac_codec
int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
Ensures that the requested seekback buffer size will be available.
Definition: aviobuf.c:982
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition: avformat.h:925
uint8_t * buf
Definition: oggdec.h:62
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:453
const struct ogg_codec ff_speex_codec
static AVStream * ost
Main libavformat public API header.
int64_t start_time
Decoding: pts of the first frame of the stream in presentation order, in stream time base...
Definition: avformat.h:915
int error_recognition
Error recognition; higher values will detect more errors but may misdetect some more or less valid pa...
Definition: avformat.h:1618
int got_data
1 if the stream got some data (non-initial packets), 0 otherwise
Definition: oggdec.h:85
static int av_size_mult(size_t a, size_t b, size_t *r)
Multiply two size_t values checking for overflow.
Definition: mem.h:669
const struct ogg_codec ff_ogm_text_codec
Definition: oggparseogm.c:212
int keyframe_seek
Definition: oggdec.h:83
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:215
static void free_stream(AVFormatContext *s, int i)
Definition: oggdec.c:66
#define av_free(p)
Definition: oggdec.h:102
static int ogg_save(AVFormatContext *s)
Definition: oggdec.c:82
int64_t page_pos
file offset of the current page
Definition: oggdec.h:107
void * priv_data
Format private data.
Definition: avformat.h:1379
static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
Definition: oggdec.c:247
static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
Definition: oggdec.c:801
uint8_t magicsize
Definition: oggdec.h:33
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: packet.h:354
static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit)
Definition: oggdec.c:892
int64_t duration
Duration of the stream, in AV_TIME_BASE fractional seconds.
Definition: avformat.h:1466
#define av_freep(p)
#define gp
Definition: regdef.h:62
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:650
int curidx
Definition: oggdec.h:106
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1023
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:356
uint8_t * av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, int size)
Allocate new information of a packet.
Definition: avpacket.c:331
int stream_index
Definition: packet.h:357
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 all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
struct ogg_stream streams[1]
Definition: oggdec.h:99
This structure stores compressed data.
Definition: packet.h:332
uint64_t avio_rl64(AVIOContext *s)
Definition: aviobuf.c:755
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:348
unsigned int bufpos
Definition: oggdec.h:64
static uint64_t ogg_gptopts(AVFormatContext *s, int i, uint64_t gp, int64_t *dts)
Definition: oggdec.h:152
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags)
Perform a binary search using av_index_search_timestamp() and AVInputFormat.read_timestamp().
Definition: utils.c:2177
#define AV_WL32(p, v)
Definition: intreadwrite.h:426