oggenc.c 29.4 KB
Newer Older
Baptiste Coudurier's avatar
Baptiste Coudurier committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Ogg muxer
 * Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at free dot fr>
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

22 23
#include <stdint.h>

24
#include "libavutil/crc.h"
25
#include "libavutil/mathematics.h"
26
#include "libavutil/opt.h"
27
#include "libavutil/random_seed.h"
28 29
#include "libavcodec/xiph.h"
#include "libavcodec/bytestream.h"
30
#include "libavcodec/flac.h"
Baptiste Coudurier's avatar
Baptiste Coudurier committed
31
#include "avformat.h"
32
#include "avio_internal.h"
33
#include "internal.h"
34
#include "vorbiscomment.h"
Baptiste Coudurier's avatar
Baptiste Coudurier committed
35

36 37
#define MAX_PAGE_SIZE 65025

38
typedef struct OGGPage {
39
    int64_t start_granule;
40 41 42 43 44 45 46 47 48
    int64_t granule;
    int stream_index;
    uint8_t flags;
    uint8_t segments_count;
    uint8_t segments[255];
    uint8_t data[MAX_PAGE_SIZE];
    uint16_t size;
} OGGPage;

49
typedef struct OGGStreamContext {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
50 51 52 53 54 55 56
    unsigned page_counter;
    uint8_t *header[3];
    int header_len[3];
    /** for theora granule */
    int kfgshift;
    int64_t last_kf_pts;
    int vrev;
57 58
    /* for VP8 granule */
    int isvp8;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
59
    int eos;
60 61
    unsigned page_count; ///< number of page buffered
    OGGPage page; ///< current page
62
    unsigned serial_num; ///< serial number
63
    int64_t last_granule; ///< last packet granule
Baptiste Coudurier's avatar
Baptiste Coudurier committed
64 65
} OGGStreamContext;

66 67 68 69 70
typedef struct OGGPageList {
    OGGPage page;
    struct OGGPageList *next;
} OGGPageList;

71
typedef struct OGGContext {
72
    const AVClass *class;
73
    OGGPageList *page_list;
74
    int pref_size; ///< preferred page size (0 => fill all segments)
75
    int64_t pref_duration;      ///< preferred page duration (0 => fill all segments)
76
    int serial_offset;
77 78
} OGGContext;

79 80
#define OFFSET(x) offsetof(OGGContext, x)
#define PARAM AV_OPT_FLAG_ENCODING_PARAM
81 82

static const AVOption options[] = {
83 84
    { "serial_offset", "serial number offset",
        OFFSET(serial_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, PARAM },
85
    { "oggpagesize", "Set preferred Ogg page size.",
86
      OFFSET(pref_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, MAX_PAGE_SIZE, PARAM},
87
    { "pagesize", "preferred page size in bytes (deprecated)",
88
        OFFSET(pref_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_PAGE_SIZE, PARAM },
89
    { "page_duration", "preferred page duration, in microseconds",
90
        OFFSET(pref_duration), AV_OPT_TYPE_INT64, { .i64 = 1000000 }, 0, INT64_MAX, PARAM },
91 92 93
    { NULL },
};

94
#define OGG_CLASS(flavor, name)\
95
static const AVClass flavor ## _muxer_class = {\
96
    .class_name = #name " muxer",\
97 98 99
    .item_name  = av_default_item_name,\
    .option     = options,\
    .version    = LIBAVUTIL_VERSION_INT,\
100 101
};

102
static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
103
{
104
    int64_t pos = avio_tell(pb);
105
    uint32_t checksum = ffio_get_checksum(pb);
106
    avio_seek(pb, crc_offset, SEEK_SET);
107
    avio_wb32(pb, checksum);
108
    avio_seek(pb, pos, SEEK_SET);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
109 110
}

111
static int ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
112
{
113
    OGGStreamContext *oggstream = s->streams[page->stream_index]->priv_data;
114
    AVIOContext *pb;
115
    int64_t crc_offset;
116 117
    int ret, size;
    uint8_t *buf;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
118

119
    ret = avio_open_dyn_buf(&pb);
120 121
    if (ret < 0)
        return ret;
122
    ffio_init_checksum(pb, ff_crc04C11DB7_update, 0);
123
    ffio_wfourcc(pb, "OggS");
124 125 126 127 128
    avio_w8(pb, 0);
    avio_w8(pb, page->flags | extra_flags);
    avio_wl64(pb, page->granule);
    avio_wl32(pb, oggstream->serial_num);
    avio_wl32(pb, oggstream->page_counter++);
129
    crc_offset = avio_tell(pb);
130 131 132 133
    avio_wl32(pb, 0); // crc
    avio_w8(pb, page->segments_count);
    avio_write(pb, page->segments, page->segments_count);
    avio_write(pb, page->data, page->size);
134 135

    ogg_update_checksum(s, pb, crc_offset);
136
    avio_flush(pb);
137

138
    size = avio_close_dyn_buf(pb, &buf);
139 140 141
    if (size < 0)
        return size;

142
    avio_write(s->pb, buf, size);
143
    avio_flush(s->pb);
144
    av_free(buf);
145
    oggstream->page_count--;
146
    return 0;
147 148
}

149 150
static int ogg_key_granule(OGGStreamContext *oggstream, int64_t granule)
{
151 152
    return (oggstream->kfgshift && !(granule & ((1<<oggstream->kfgshift)-1))) ||
           (oggstream->isvp8    && !((granule >> 3) & 0x07ffffff));
153 154
}

155
static int64_t ogg_granule_to_timestamp(OGGStreamContext *oggstream, int64_t granule)
156 157
{
    if (oggstream->kfgshift)
158 159
        return (granule>>oggstream->kfgshift) +
            (granule & ((1<<oggstream->kfgshift)-1));
160 161
    else if (oggstream->isvp8)
        return granule >> 32;
162
    else
163
        return granule;
164 165 166 167 168 169 170 171 172 173 174
}

static int ogg_compare_granule(AVFormatContext *s, OGGPage *next, OGGPage *page)
{
    AVStream *st2 = s->streams[next->stream_index];
    AVStream *st  = s->streams[page->stream_index];
    int64_t next_granule, cur_granule;

    if (next->granule == -1 || page->granule == -1)
        return 0;

175
    next_granule = av_rescale_q(ogg_granule_to_timestamp(st2->priv_data, next->granule),
176
                                st2->time_base, AV_TIME_BASE_Q);
177
    cur_granule  = av_rescale_q(ogg_granule_to_timestamp(st->priv_data, page->granule),
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
                                st ->time_base, AV_TIME_BASE_Q);
    return next_granule > cur_granule;
}

static int ogg_reset_cur_page(OGGStreamContext *oggstream)
{
    oggstream->page.granule = -1;
    oggstream->page.flags = 0;
    oggstream->page.segments_count = 0;
    oggstream->page.size = 0;
    return 0;
}

static int ogg_buffer_page(AVFormatContext *s, OGGStreamContext *oggstream)
{
    OGGContext *ogg = s->priv_data;
    OGGPageList **p = &ogg->page_list;
    OGGPageList *l = av_mallocz(sizeof(*l));

    if (!l)
        return AVERROR(ENOMEM);
    l->page = oggstream->page;

201
    oggstream->page.start_granule = ogg_granule_to_timestamp(oggstream, oggstream->page.granule);
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    oggstream->page_count++;
    ogg_reset_cur_page(oggstream);

    while (*p) {
        if (ogg_compare_granule(s, &(*p)->page, &l->page))
            break;
        p = &(*p)->next;
    }
    l->next = *p;
    *p = l;

    return 0;
}

static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
217 218
                           uint8_t *data, unsigned size, int64_t granule,
                           int header)
219 220
{
    OGGStreamContext *oggstream = st->priv_data;
221
    OGGContext *ogg = s->priv_data;
222 223
    int total_segments = size / 255 + 1;
    uint8_t *p = data;
224 225 226
    int i, segments, len, flush = 0;

    // Handles VFR by flushing page because this frame needs to have a timestamp
227
    // For theora and VP8, keyframes also need to have a timestamp to correctly mark
228 229
    // them as such, otherwise seeking will not work correctly at the very
    // least with old libogg versions.
230
    // Do not try to flush header packets though, that will create broken files.
231
    if ((st->codecpar->codec_id == AV_CODEC_ID_THEORA || st->codecpar->codec_id == AV_CODEC_ID_VP8) && !header &&
232 233 234
        (ogg_granule_to_timestamp(oggstream, granule) >
         ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1 ||
         ogg_key_granule(oggstream, granule))) {
235 236 237 238
        if (oggstream->page.granule != -1)
            ogg_buffer_page(s, oggstream);
        flush = 1;
    }
239

240 241 242 243 244 245
    // avoid a continued page
    if (!header && oggstream->page.size > 0 &&
        MAX_PAGE_SIZE - oggstream->page.size < size) {
        ogg_buffer_page(s, oggstream);
    }

246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
    for (i = 0; i < total_segments; ) {
        OGGPage *page = &oggstream->page;

        segments = FFMIN(total_segments - i, 255 - page->segments_count);

        if (i && !page->segments_count)
            page->flags |= 1; // continued packet

        memset(page->segments+page->segments_count, 255, segments - 1);
        page->segments_count += segments - 1;

        len = FFMIN(size, segments*255);
        page->segments[page->segments_count++] = len - (segments-1)*255;
        memcpy(page->data+page->size, p, len);
        p += len;
        size -= len;
        i += segments;
        page->size += len;

        if (i == total_segments)
            page->granule = granule;

268
        {
269 270 271 272
            AVStream *st = s->streams[page->stream_index];

            int64_t start = av_rescale_q(page->start_granule, st->time_base,
                                         AV_TIME_BASE_Q);
273 274
            int64_t next  = av_rescale_q(ogg_granule_to_timestamp(oggstream, page->granule),
                                         st->time_base, AV_TIME_BASE_Q);
275

276
            if (page->segments_count == 255) {
277
                ogg_buffer_page(s, oggstream);
278 279 280 281 282
            } else if (!header) {
                if ((ogg->pref_size     > 0 && page->size   >= ogg->pref_size) ||
                    (ogg->pref_duration > 0 && next - start >= ogg->pref_duration)) {
                    ogg_buffer_page(s, oggstream);
                }
283
            }
284 285
        }
    }
286 287 288 289

    if (flush && oggstream->page.granule != -1)
        ogg_buffer_page(s, oggstream);

290
    return 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
291 292
}

293
static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact,
294 295
                                        int *header_len, AVDictionary **m, int framing_bit,
                                        AVChapter **chapters, unsigned int nb_chapters)
296 297
{
    const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
298
    int64_t size;
299 300
    uint8_t *p, *p0;

301 302
    ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL);

303
    size = offset + ff_vorbiscomment_length(*m, vendor, chapters, nb_chapters) + framing_bit;
304 305
    if (size > INT_MAX)
        return NULL;
306 307 308 309 310 311
    p = av_mallocz(size);
    if (!p)
        return NULL;
    p0 = p;

    p += offset;
312
    ff_vorbiscomment_write(&p, m, vendor, chapters, nb_chapters);
313 314
    if (framing_bit)
        bytestream_put_byte(&p, 1);
315 316 317 318 319

    *header_len = size;
    return p0;
}

320
static int ogg_build_flac_headers(AVCodecParameters *par,
321
                                  OGGStreamContext *oggstream, int bitexact,
322
                                  AVDictionary **m)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
323 324
{
    uint8_t *p;
325

326
    if (par->extradata_size < FLAC_STREAMINFO_SIZE)
327
        return AVERROR(EINVAL);
328 329

    // first packet: STREAMINFO
330 331
    oggstream->header_len[0] = 51;
    oggstream->header[0] = av_mallocz(51); // per ogg flac specs
Baptiste Coudurier's avatar
Baptiste Coudurier committed
332
    p = oggstream->header[0];
333
    if (!p)
334
        return AVERROR(ENOMEM);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
335 336 337 338 339 340 341 342
    bytestream_put_byte(&p, 0x7F);
    bytestream_put_buffer(&p, "FLAC", 4);
    bytestream_put_byte(&p, 1); // major version
    bytestream_put_byte(&p, 0); // minor version
    bytestream_put_be16(&p, 1); // headers packets without this one
    bytestream_put_buffer(&p, "fLaC", 4);
    bytestream_put_byte(&p, 0x00); // streaminfo
    bytestream_put_be24(&p, 34);
343
    bytestream_put_buffer(&p, par->extradata, FLAC_STREAMINFO_SIZE);
344 345

    // second packet: VorbisComment
346
    p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m, 0, NULL, 0);
347
    if (!p)
348
        return AVERROR(ENOMEM);
349
    oggstream->header[1] = p;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
350 351
    bytestream_put_byte(&p, 0x84); // last metadata block and vorbis comment
    bytestream_put_be24(&p, oggstream->header_len[1] - 4);
352 353 354 355 356 357

    return 0;
}

#define SPEEX_HEADER_SIZE 80

358
static int ogg_build_speex_headers(AVCodecParameters *par,
359
                                   OGGStreamContext *oggstream, int bitexact,
360
                                   AVDictionary **m)
361 362 363
{
    uint8_t *p;

364
    if (par->extradata_size < SPEEX_HEADER_SIZE)
365
        return AVERROR_INVALIDDATA;
366 367 368 369

    // first packet: Speex header
    p = av_mallocz(SPEEX_HEADER_SIZE);
    if (!p)
370
        return AVERROR(ENOMEM);
371 372
    oggstream->header[0] = p;
    oggstream->header_len[0] = SPEEX_HEADER_SIZE;
373
    bytestream_put_buffer(&p, par->extradata, SPEEX_HEADER_SIZE);
374 375 376
    AV_WL32(&oggstream->header[0][68], 0);  // set extra_headers to 0

    // second packet: VorbisComment
377
    p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0, NULL, 0);
378
    if (!p)
379
        return AVERROR(ENOMEM);
380
    oggstream->header[1] = p;
381

Baptiste Coudurier's avatar
Baptiste Coudurier committed
382 383 384
    return 0;
}

385 386
#define OPUS_HEADER_SIZE 19

387
static int ogg_build_opus_headers(AVCodecParameters *par,
388
                                  OGGStreamContext *oggstream, int bitexact,
389 390
                                  AVDictionary **m, AVChapter **chapters,
                                  unsigned int nb_chapters)
391 392 393
{
    uint8_t *p;

394
    if (par->extradata_size < OPUS_HEADER_SIZE)
395
        return AVERROR_INVALIDDATA;
396 397

    /* first packet: Opus header */
398
    p = av_mallocz(par->extradata_size);
399 400 401
    if (!p)
        return AVERROR(ENOMEM);
    oggstream->header[0] = p;
402 403
    oggstream->header_len[0] = par->extradata_size;
    bytestream_put_buffer(&p, par->extradata, par->extradata_size);
404 405

    /* second packet: VorbisComment */
406
    p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0, chapters, nb_chapters);
407 408 409 410 411 412 413 414
    if (!p)
        return AVERROR(ENOMEM);
    oggstream->header[1] = p;
    bytestream_put_buffer(&p, "OpusTags", 8);

    return 0;
}

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
#define VP8_HEADER_SIZE 26

static int ogg_build_vp8_headers(AVFormatContext *s, AVStream *st,
                                 OGGStreamContext *oggstream, int bitexact)
{
    AVCodecParameters *par = st->codecpar;
    uint8_t *p;

    /* first packet: VP8 header */
    p = av_mallocz(VP8_HEADER_SIZE);
    if (!p)
        return AVERROR(ENOMEM);
    oggstream->header[0] = p;
    oggstream->header_len[0] = VP8_HEADER_SIZE;
    bytestream_put_byte(&p, 0x4f); // HDRID
    bytestream_put_buffer(&p, "VP80", 4); // Identifier
    bytestream_put_byte(&p, 1); // HDRTYP
    bytestream_put_byte(&p, 1); // VMAJ
    bytestream_put_byte(&p, 0); // VMIN
    bytestream_put_be16(&p, par->width);
    bytestream_put_be16(&p, par->height);
    bytestream_put_be24(&p, par->sample_aspect_ratio.num);
    bytestream_put_be24(&p, par->sample_aspect_ratio.den);
    if (st->r_frame_rate.num > 0 && st->r_frame_rate.den > 0) {
        // OggVP8 requires pts to increase by 1 per visible frame, so use the least common
        // multiple framerate if available.
        av_log(s, AV_LOG_DEBUG, "Changing time base from %d/%d to %d/%d\n",
               st->time_base.num, st->time_base.den,
               st->r_frame_rate.den, st->r_frame_rate.num);
        avpriv_set_pts_info(st, 64, st->r_frame_rate.den, st->r_frame_rate.num);
    }
    bytestream_put_be32(&p, st->time_base.den);
    bytestream_put_be32(&p, st->time_base.num);

    /* optional second packet: VorbisComment */
    if (av_dict_get(st->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
451
        p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0, NULL, 0);
452 453 454 455 456 457 458 459 460 461 462 463 464 465
        if (!p)
            return AVERROR(ENOMEM);
        oggstream->header[1] = p;
        bytestream_put_byte(&p, 0x4f); // HDRID
        bytestream_put_buffer(&p, "VP80", 4); // Identifier
        bytestream_put_byte(&p, 2); // HDRTYP
        bytestream_put_byte(&p, 0x20);
    }

    oggstream->isvp8 = 1;

    return 0;
}

466 467 468 469 470 471 472 473 474 475 476 477 478 479
static void ogg_write_pages(AVFormatContext *s, int flush)
{
    OGGContext *ogg = s->priv_data;
    OGGPageList *next, *p;

    if (!ogg->page_list)
        return;

    for (p = ogg->page_list; p; ) {
        OGGStreamContext *oggstream =
            s->streams[p->page.stream_index]->priv_data;
        if (oggstream->page_count < 2 && !flush)
            break;
        ogg_write_page(s, &p->page,
480
                       flush == 1 && oggstream->page_count == 1 ? 4 : 0); // eos
481 482 483 484 485 486 487
        next = p->next;
        av_freep(&p);
        p = next;
    }
    ogg->page_list = p;
}

488
static int ogg_init(AVFormatContext *s)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
489
{
490
    OGGContext *ogg = s->priv_data;
491
    OGGStreamContext *oggstream = NULL;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
492
    int i, j;
493

494 495 496
    if (ogg->pref_size)
        av_log(s, AV_LOG_WARNING, "The pagesize option is deprecated\n");

Baptiste Coudurier's avatar
Baptiste Coudurier committed
497 498
    for (i = 0; i < s->nb_streams; i++) {
        AVStream *st = s->streams[i];
499
        unsigned serial_num = i + ogg->serial_offset;
500

501
        if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
502
            if (st->codecpar->codec_id == AV_CODEC_ID_OPUS)
503 504 505
                /* Opus requires a fixed 48kHz clock */
                avpriv_set_pts_info(st, 64, 1, 48000);
            else
506
                avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
507
        }
508

509 510 511 512
        if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS &&
            st->codecpar->codec_id != AV_CODEC_ID_THEORA &&
            st->codecpar->codec_id != AV_CODEC_ID_SPEEX  &&
            st->codecpar->codec_id != AV_CODEC_ID_FLAC   &&
513 514
            st->codecpar->codec_id != AV_CODEC_ID_OPUS   &&
            st->codecpar->codec_id != AV_CODEC_ID_VP8) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
515
            av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i);
516
            return AVERROR(EINVAL);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
517 518
        }

519 520
        if ((!st->codecpar->extradata || !st->codecpar->extradata_size) &&
            st->codecpar->codec_id != AV_CODEC_ID_VP8) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
521
            av_log(s, AV_LOG_ERROR, "No extradata present\n");
522
            return AVERROR_INVALIDDATA;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
523 524
        }
        oggstream = av_mallocz(sizeof(*oggstream));
525 526 527
        if (!oggstream)
            return AVERROR(ENOMEM);

528
        oggstream->page.stream_index = i;
529

530
        if (!(s->flags & AVFMT_FLAG_BITEXACT))
531 532 533 534 535 536 537 538 539 540
            do {
                serial_num = av_get_random_seed();
                for (j = 0; j < i; j++) {
                    OGGStreamContext *sc = s->streams[j]->priv_data;
                    if (serial_num == sc->serial_num)
                        break;
                }
            } while (j < i);
        oggstream->serial_num = serial_num;

541 542
        av_dict_copy(&st->metadata, s->metadata, AV_DICT_DONT_OVERWRITE);

Baptiste Coudurier's avatar
Baptiste Coudurier committed
543
        st->priv_data = oggstream;
544 545
        if (st->codecpar->codec_id == AV_CODEC_ID_FLAC) {
            int err = ogg_build_flac_headers(st->codecpar, oggstream,
546
                                             s->flags & AVFMT_FLAG_BITEXACT,
547
                                             &st->metadata);
548
            if (err) {
549
                av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
550
                av_freep(&st->priv_data);
551
                return err;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
552
            }
553 554
        } else if (st->codecpar->codec_id == AV_CODEC_ID_SPEEX) {
            int err = ogg_build_speex_headers(st->codecpar, oggstream,
555
                                              s->flags & AVFMT_FLAG_BITEXACT,
556
                                              &st->metadata);
557 558 559 560 561
            if (err) {
                av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n");
                av_freep(&st->priv_data);
                return err;
            }
562 563
        } else if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) {
            int err = ogg_build_opus_headers(st->codecpar, oggstream,
564
                                             s->flags & AVFMT_FLAG_BITEXACT,
565
                                             &st->metadata, s->chapters, s->nb_chapters);
566 567 568 569 570
            if (err) {
                av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n");
                av_freep(&st->priv_data);
                return err;
            }
571 572 573 574 575 576 577 578
        } else if (st->codecpar->codec_id == AV_CODEC_ID_VP8) {
            int err = ogg_build_vp8_headers(s, st, oggstream,
                                            s->flags & AVFMT_FLAG_BITEXACT);
            if (err) {
                av_log(s, AV_LOG_ERROR, "Error writing VP8 headers\n");
                av_freep(&st->priv_data);
                return err;
            }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
579
        } else {
580
            uint8_t *p;
581 582 583
            const char *cstr = st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? "vorbis" : "theora";
            int header_type = st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? 3 : 0x81;
            int framing_bit = st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? 1 : 0;
584

585 586
            if (avpriv_split_xiph_headers(st->codecpar->extradata, st->codecpar->extradata_size,
                                      st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? 30 : 42,
587
                                      (const uint8_t**)oggstream->header, oggstream->header_len) < 0) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
588 589
                av_log(s, AV_LOG_ERROR, "Extradata corrupted\n");
                av_freep(&st->priv_data);
590
                return AVERROR_INVALIDDATA;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
591
            }
592

593
            p = ogg_write_vorbiscomment(7, s->flags & AVFMT_FLAG_BITEXACT,
594
                                        &oggstream->header_len[1], &st->metadata,
595
                                        framing_bit, NULL, 0);
596
            oggstream->header[1] = p;
597 598 599 600 601 602
            if (!p)
                return AVERROR(ENOMEM);

            bytestream_put_byte(&p, header_type);
            bytestream_put_buffer(&p, cstr, 6);

603
            if (st->codecpar->codec_id == AV_CODEC_ID_THEORA) {
604 605 606 607 608 609 610 611
                int den = AV_RB32(oggstream->header[0] + 22), num = AV_RB32(oggstream->header[0] + 26);
                /* Make sure to use time base stored in the Theora stream header to write
                   correct timestamps */
                if (st->time_base.num != num || st->time_base.den != den) {
                    av_log(s, AV_LOG_DEBUG, "Changing time base from %d/%d to %d/%d\n",
                           st->time_base.num, st->time_base.den, num, den);
                    avpriv_set_pts_info(st, 64, num, den);
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
612 613 614 615 616 617 618 619 620
                /** KFGSHIFT is the width of the less significant section of the granule position
                    The less significant section is the frame count since the last keyframe */
                oggstream->kfgshift = ((oggstream->header[0][40]&3)<<3)|(oggstream->header[0][41]>>5);
                oggstream->vrev = oggstream->header[0][9];
                av_log(s, AV_LOG_DEBUG, "theora kfgshift %d, vrev %d\n",
                       oggstream->kfgshift, oggstream->vrev);
            }
        }
    }
621

622 623 624 625 626 627 628 629
    return 0;
}

static int ogg_write_header(AVFormatContext *s)
{
    OGGStreamContext *oggstream = NULL;
    int i, j;

630
    for (j = 0; j < s->nb_streams; j++) {
631
        oggstream = s->streams[j]->priv_data;
632
        ogg_buffer_data(s, s->streams[j], oggstream->header[0],
633
                        oggstream->header_len[0], 0, 1);
634 635 636 637 638
        oggstream->page.flags |= 2; // bos
        ogg_buffer_page(s, oggstream);
    }
    for (j = 0; j < s->nb_streams; j++) {
        AVStream *st = s->streams[j];
639
        oggstream = st->priv_data;
640
        for (i = 1; i < 3; i++) {
641
            if (oggstream->header_len[i])
642
                ogg_buffer_data(s, st, oggstream->header[i],
643
                                oggstream->header_len[i], 0, 1);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
644
        }
645
        ogg_buffer_page(s, oggstream);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
646
    }
647 648 649

    oggstream->page.start_granule = AV_NOPTS_VALUE;

650
    ogg_write_pages(s, 2);
651

Baptiste Coudurier's avatar
Baptiste Coudurier committed
652 653 654
    return 0;
}

655
static int ogg_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
656 657 658
{
    AVStream *st = s->streams[pkt->stream_index];
    OGGStreamContext *oggstream = st->priv_data;
659
    int ret;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
660 661
    int64_t granule;

662
    if (st->codecpar->codec_id == AV_CODEC_ID_THEORA) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
663 664
        int64_t pts = oggstream->vrev < 1 ? pkt->pts : pkt->pts + pkt->duration;
        int pframe_count;
665
        if (pkt->flags & AV_PKT_FLAG_KEY)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
666 667 668 669 670 671 672 673
            oggstream->last_kf_pts = pts;
        pframe_count = pts - oggstream->last_kf_pts;
        // prevent frame count from overflow if key frame flag is not set
        if (pframe_count >= (1<<oggstream->kfgshift)) {
            oggstream->last_kf_pts += pframe_count;
            pframe_count = 0;
        }
        granule = (oggstream->last_kf_pts<<oggstream->kfgshift) | pframe_count;
674
    } else if (st->codecpar->codec_id == AV_CODEC_ID_OPUS)
675
        granule = pkt->pts + pkt->duration +
676 677
                  av_rescale_q(st->codecpar->initial_padding,
                               (AVRational){ 1, st->codecpar->sample_rate },
678
                               st->time_base);
679 680 681 682 683 684 685 686 687 688 689 690
    else if (st->codecpar->codec_id == AV_CODEC_ID_VP8) {
        int64_t pts, invcnt, dist;
        int visible;

        visible = (pkt->data[0] >> 4) & 1;
        pts     = pkt->pts + pkt->duration;
        invcnt  = (oggstream->last_granule >> 30) & 3;
        invcnt  = visible ? 3 : (invcnt == 3 ? 0 : invcnt + 1);
        dist    = (pkt->flags & AV_PKT_FLAG_KEY) ? 0 : ((oggstream->last_granule >> 3) & 0x07ffffff) + 1;

        granule = (pts << 32) | (invcnt << 30) | (dist << 3);
    } else
Baptiste Coudurier's avatar
Baptiste Coudurier committed
691 692
        granule = pkt->pts + pkt->duration;

693 694 695
    if (oggstream->page.start_granule == AV_NOPTS_VALUE)
        oggstream->page.start_granule = pkt->pts;

696
    ret = ogg_buffer_data(s, st, pkt->data, pkt->size, granule, 0);
697 698
    if (ret < 0)
        return ret;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
699

700
    ogg_write_pages(s, 0);
701

702 703
    oggstream->last_granule = granule;

704
    return 0;
705 706
}

707 708 709 710 711 712 713 714 715 716 717 718 719 720
static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt)
{
    int i;

    if (pkt)
        return ogg_write_packet_internal(s, pkt);

    for (i = 0; i < s->nb_streams; i++) {
        OGGStreamContext *oggstream = s->streams[i]->priv_data;
        if (oggstream->page.segments_count)
            ogg_buffer_page(s, oggstream);
    }

    ogg_write_pages(s, 2);
721
    return 1;
722 723
}

724
static int ogg_write_trailer(AVFormatContext *s)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
725
{
726
    int i;
727

728 729 730 731 732 733 734
    /* flush current page if needed */
    for (i = 0; i < s->nb_streams; i++) {
        OGGStreamContext *oggstream = s->streams[i]->priv_data;

        if (oggstream->page.size > 0)
            ogg_buffer_page(s, oggstream);
    }
735

736
    ogg_write_pages(s, 1);
737

738 739 740 741 742 743 744
    return 0;
}

static void ogg_free(AVFormatContext *s)
{
    int i;

Baptiste Coudurier's avatar
Baptiste Coudurier committed
745 746 747
    for (i = 0; i < s->nb_streams; i++) {
        AVStream *st = s->streams[i];
        OGGStreamContext *oggstream = st->priv_data;
748 749
        if (!oggstream)
            continue;
750 751
        if (st->codecpar->codec_id == AV_CODEC_ID_FLAC ||
            st->codecpar->codec_id == AV_CODEC_ID_SPEEX ||
752 753
            st->codecpar->codec_id == AV_CODEC_ID_OPUS ||
            st->codecpar->codec_id == AV_CODEC_ID_VP8) {
754
            av_freep(&oggstream->header[0]);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
755
        }
756
        av_freep(&oggstream->header[1]);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
757 758 759 760
        av_freep(&st->priv_data);
    }
}

761
#if CONFIG_OGG_MUXER
762
OGG_CLASS(ogg, Ogg)
763
AVOutputFormat ff_ogg_muxer = {
764 765 766
    .name              = "ogg",
    .long_name         = NULL_IF_CONFIG_SMALL("Ogg"),
    .mime_type         = "application/ogg",
767 768 769 770
    .extensions        = "ogg"
#if !CONFIG_OGV_MUXER
                         ",ogv"
#endif
771
#if !CONFIG_SPX_MUXER
772 773 774 775 776 777
                         ",spx"
#endif
#if !CONFIG_OPUS_MUXER
                         ",opus"
#endif
                         ,
778
    .priv_data_size    = sizeof(OGGContext),
779 780
    .audio_codec       = CONFIG_LIBVORBIS_ENCODER ?
                         AV_CODEC_ID_VORBIS : AV_CODEC_ID_FLAC,
781
    .video_codec       = AV_CODEC_ID_THEORA,
782
    .init              = ogg_init,
783 784 785
    .write_header      = ogg_write_header,
    .write_packet      = ogg_write_packet,
    .write_trailer     = ogg_write_trailer,
786
    .deinit            = ogg_free,
787
    .flags             = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
788
    .priv_class        = &ogg_muxer_class,
Baptiste Coudurier's avatar
Baptiste Coudurier committed
789
};
790 791
#endif

Carl Eugen Hoyos's avatar
Carl Eugen Hoyos committed
792
#if CONFIG_OGA_MUXER
793
OGG_CLASS(oga, Ogg audio)
Carl Eugen Hoyos's avatar
Carl Eugen Hoyos committed
794 795
AVOutputFormat ff_oga_muxer = {
    .name              = "oga",
796
    .long_name         = NULL_IF_CONFIG_SMALL("Ogg Audio"),
Carl Eugen Hoyos's avatar
Carl Eugen Hoyos committed
797 798 799
    .mime_type         = "audio/ogg",
    .extensions        = "oga",
    .priv_data_size    = sizeof(OGGContext),
800
    .audio_codec       = AV_CODEC_ID_FLAC,
801
    .init              = ogg_init,
Carl Eugen Hoyos's avatar
Carl Eugen Hoyos committed
802 803 804
    .write_header      = ogg_write_header,
    .write_packet      = ogg_write_packet,
    .write_trailer     = ogg_write_trailer,
805
    .deinit            = ogg_free,
806
    .flags             = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH,
Carl Eugen Hoyos's avatar
Carl Eugen Hoyos committed
807 808 809 810
    .priv_class        = &oga_muxer_class,
};
#endif

811 812 813 814 815 816 817 818 819 820
#if CONFIG_OGV_MUXER
OGG_CLASS(ogv, Ogg video)
AVOutputFormat ff_ogv_muxer = {
    .name              = "ogv",
    .long_name         = NULL_IF_CONFIG_SMALL("Ogg Video"),
    .mime_type         = "video/ogg",
    .extensions        = "ogv",
    .priv_data_size    = sizeof(OGGContext),
    .audio_codec       = CONFIG_LIBVORBIS_ENCODER ?
                         AV_CODEC_ID_VORBIS : AV_CODEC_ID_FLAC,
821 822
    .video_codec       = CONFIG_LIBTHEORA_ENCODER ?
                         AV_CODEC_ID_THEORA : AV_CODEC_ID_VP8,
823
    .init              = ogg_init,
824 825 826
    .write_header      = ogg_write_header,
    .write_packet      = ogg_write_packet,
    .write_trailer     = ogg_write_trailer,
827
    .deinit            = ogg_free,
828
    .flags             = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
829 830 831 832
    .priv_class        = &ogv_muxer_class,
};
#endif

833
#if CONFIG_SPX_MUXER
834
OGG_CLASS(spx, Ogg Speex)
835 836 837
AVOutputFormat ff_spx_muxer = {
    .name              = "spx",
    .long_name         = NULL_IF_CONFIG_SMALL("Ogg Speex"),
838 839 840 841
    .mime_type         = "audio/ogg",
    .extensions        = "spx",
    .priv_data_size    = sizeof(OGGContext),
    .audio_codec       = AV_CODEC_ID_SPEEX,
842
    .init              = ogg_init,
843 844 845
    .write_header      = ogg_write_header,
    .write_packet      = ogg_write_packet,
    .write_trailer     = ogg_write_trailer,
846
    .deinit            = ogg_free,
847
    .flags             = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH,
848
    .priv_class        = &spx_muxer_class,
849 850 851 852
};
#endif

#if CONFIG_OPUS_MUXER
853
OGG_CLASS(opus, Ogg Opus)
854 855
AVOutputFormat ff_opus_muxer = {
    .name              = "opus",
856
    .long_name         = NULL_IF_CONFIG_SMALL("Ogg Opus"),
857 858 859 860
    .mime_type         = "audio/ogg",
    .extensions        = "opus",
    .priv_data_size    = sizeof(OGGContext),
    .audio_codec       = AV_CODEC_ID_OPUS,
861
    .init              = ogg_init,
862 863 864
    .write_header      = ogg_write_header,
    .write_packet      = ogg_write_packet,
    .write_trailer     = ogg_write_trailer,
865
    .deinit            = ogg_free,
866
    .flags             = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH,
867 868 869
    .priv_class        = &opus_muxer_class,
};
#endif