oggenc.c 29.6 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 136

    ogg_update_checksum(s, pb, crc_offset);

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

141
    avio_write(s->pb, buf, size);
142
    avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
143
    av_free(buf);
144
    oggstream->page_count--;
145
    return 0;
146 147
}

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

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

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;

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

200
    oggstream->page.start_granule = ogg_granule_to_timestamp(oggstream, oggstream->page.granule);
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
    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,
216 217
                           uint8_t *data, unsigned size, int64_t granule,
                           int header)
218 219
{
    OGGStreamContext *oggstream = st->priv_data;
220
    OGGContext *ogg = s->priv_data;
221 222
    int total_segments = size / 255 + 1;
    uint8_t *p = data;
223 224 225
    int i, segments, len, flush = 0;

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

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

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
    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;

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

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

275
            if (page->segments_count == 255) {
276
                ogg_buffer_page(s, oggstream);
277 278 279 280 281
            } 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);
                }
282
            }
283 284
        }
    }
285 286 287 288

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

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

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

300 301
    ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL);

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

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

    *header_len = size;
    return p0;
}

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

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

    // first packet: STREAMINFO
329 330
    oggstream->header_len[0] = 51;
    oggstream->header[0] = av_mallocz(51); // per ogg flac specs
Baptiste Coudurier's avatar
Baptiste Coudurier committed
331
    p = oggstream->header[0];
332
    if (!p)
333
        return AVERROR(ENOMEM);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
334 335 336 337 338 339 340 341
    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);
342
    bytestream_put_buffer(&p, par->extradata, FLAC_STREAMINFO_SIZE);
343 344

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

    return 0;
}

#define SPEEX_HEADER_SIZE 80

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

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

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

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

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

384 385
#define OPUS_HEADER_SIZE 19

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

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

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

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

    return 0;
}

414 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
#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)) {
450
        p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0, NULL, 0);
451 452 453 454 455 456 457 458 459 460 461 462 463 464
        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;
}

465 466 467 468 469 470 471 472 473 474 475 476 477 478
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,
479
                       flush == 1 && oggstream->page_count == 1 ? 4 : 0); // eos
480 481 482 483 484 485 486
        next = p->next;
        av_freep(&p);
        p = next;
    }
    ogg->page_list = p;
}

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

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

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

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

508 509 510 511
        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   &&
512 513
            st->codecpar->codec_id != AV_CODEC_ID_OPUS   &&
            st->codecpar->codec_id != AV_CODEC_ID_VP8) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
514
            av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i);
515
            return AVERROR(EINVAL);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
516 517
        }

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

527
        oggstream->page.stream_index = i;
528

529
        if (!(s->flags & AVFMT_FLAG_BITEXACT))
530 531 532 533 534 535 536 537 538 539
            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;

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
542
        st->priv_data = oggstream;
543 544
        if (st->codecpar->codec_id == AV_CODEC_ID_FLAC) {
            int err = ogg_build_flac_headers(st->codecpar, oggstream,
545
                                             s->flags & AVFMT_FLAG_BITEXACT,
546
                                             &st->metadata);
547
            if (err) {
548
                av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
549
                av_freep(&st->priv_data);
550
                return err;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
551
            }
552 553
        } else if (st->codecpar->codec_id == AV_CODEC_ID_SPEEX) {
            int err = ogg_build_speex_headers(st->codecpar, oggstream,
554
                                              s->flags & AVFMT_FLAG_BITEXACT,
555
                                              &st->metadata);
556 557 558 559 560
            if (err) {
                av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n");
                av_freep(&st->priv_data);
                return err;
            }
561 562
        } else if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) {
            int err = ogg_build_opus_headers(st->codecpar, oggstream,
563
                                             s->flags & AVFMT_FLAG_BITEXACT,
564
                                             &st->metadata, s->chapters, s->nb_chapters);
565 566 567 568 569
            if (err) {
                av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n");
                av_freep(&st->priv_data);
                return err;
            }
570 571 572 573 574 575 576 577
        } 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
578
        } else {
579
            uint8_t *p;
580 581 582
            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;
583

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

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

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

602
            if (st->codecpar->codec_id == AV_CODEC_ID_THEORA) {
603 604 605 606 607 608 609 610
                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
611 612 613 614 615 616 617 618 619
                /** 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);
            }
        }
    }
620

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

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

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

    oggstream->page.start_granule = AV_NOPTS_VALUE;

649
    ogg_write_pages(s, 2);
650

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

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

661
    if (st->codecpar->codec_id == AV_CODEC_ID_THEORA) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
662 663
        int64_t pts = oggstream->vrev < 1 ? pkt->pts : pkt->pts + pkt->duration;
        int pframe_count;
664
        if (pkt->flags & AV_PKT_FLAG_KEY)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
665 666 667 668 669 670 671 672
            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;
673
    } else if (st->codecpar->codec_id == AV_CODEC_ID_OPUS)
674
        granule = pkt->pts + pkt->duration +
675 676
                  av_rescale_q(st->codecpar->initial_padding,
                               (AVRational){ 1, st->codecpar->sample_rate },
677
                               st->time_base);
678 679 680 681 682 683 684 685 686 687 688 689
    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
690 691
        granule = pkt->pts + pkt->duration;

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

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

699
    ogg_write_pages(s, 0);
700

701 702
    oggstream->last_granule = granule;

703
    return 0;
704 705
}

706 707 708 709 710 711 712 713 714 715 716 717 718 719
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);
720
    return 1;
721 722
}

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

727 728 729 730 731 732 733
    /* 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);
    }
734

735
    ogg_write_pages(s, 1);
736

737 738 739 740 741
    return 0;
}

static void ogg_free(AVFormatContext *s)
{
742 743
    OGGContext *ogg = s->priv_data;
    OGGPageList *p = ogg->page_list;
744 745
    int i;

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

    while (p) {
        OGGPageList *next = p->next;
        av_free(p);
        p = next;
    }
    ogg->page_list = NULL;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
767 768
}

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

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

819 820 821 822 823 824 825 826 827 828
#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,
829 830
    .video_codec       = CONFIG_LIBTHEORA_ENCODER ?
                         AV_CODEC_ID_THEORA : AV_CODEC_ID_VP8,
831
    .init              = ogg_init,
832 833 834
    .write_header      = ogg_write_header,
    .write_packet      = ogg_write_packet,
    .write_trailer     = ogg_write_trailer,
835
    .deinit            = ogg_free,
836
    .flags             = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
837 838 839 840
    .priv_class        = &ogv_muxer_class,
};
#endif

841
#if CONFIG_SPX_MUXER
842
OGG_CLASS(spx, Ogg Speex)
843 844 845
AVOutputFormat ff_spx_muxer = {
    .name              = "spx",
    .long_name         = NULL_IF_CONFIG_SMALL("Ogg Speex"),
846 847 848 849
    .mime_type         = "audio/ogg",
    .extensions        = "spx",
    .priv_data_size    = sizeof(OGGContext),
    .audio_codec       = AV_CODEC_ID_SPEEX,
850
    .init              = ogg_init,
851 852 853
    .write_header      = ogg_write_header,
    .write_packet      = ogg_write_packet,
    .write_trailer     = ogg_write_trailer,
854
    .deinit            = ogg_free,
855
    .flags             = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH,
856
    .priv_class        = &spx_muxer_class,
857 858 859 860
};
#endif

#if CONFIG_OPUS_MUXER
861
OGG_CLASS(opus, Ogg Opus)
862 863
AVOutputFormat ff_opus_muxer = {
    .name              = "opus",
864
    .long_name         = NULL_IF_CONFIG_SMALL("Ogg Opus"),
865 866 867 868
    .mime_type         = "audio/ogg",
    .extensions        = "opus",
    .priv_data_size    = sizeof(OGGContext),
    .audio_codec       = AV_CODEC_ID_OPUS,
869
    .init              = ogg_init,
870 871 872
    .write_header      = ogg_write_header,
    .write_packet      = ogg_write_packet,
    .write_trailer     = ogg_write_trailer,
873
    .deinit            = ogg_free,
874
    .flags             = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH,
875 876 877
    .priv_class        = &opus_muxer_class,
};
#endif