oggenc.c 14.8 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
#include "libavutil/crc.h"
23
#include "libavutil/random_seed.h"
24 25
#include "libavcodec/xiph.h"
#include "libavcodec/bytestream.h"
26
#include "libavcodec/flac.h"
Baptiste Coudurier's avatar
Baptiste Coudurier committed
27
#include "avformat.h"
28
#include "internal.h"
29
#include "vorbiscomment.h"
Baptiste Coudurier's avatar
Baptiste Coudurier committed
30

31 32 33 34 35 36 37 38 39 40 41 42
#define MAX_PAGE_SIZE 65025

typedef struct {
    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;

Baptiste Coudurier's avatar
Baptiste Coudurier committed
43 44 45 46 47 48 49 50
typedef struct {
    unsigned page_counter;
    uint8_t *header[3];
    int header_len[3];
    /** for theora granule */
    int kfgshift;
    int64_t last_kf_pts;
    int vrev;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
51
    int eos;
52 53
    unsigned page_count; ///< number of page buffered
    OGGPage page; ///< current page
54
    unsigned serial_num; ///< serial number
Baptiste Coudurier's avatar
Baptiste Coudurier committed
55 56
} OGGStreamContext;

57 58 59 60 61 62 63 64 65
typedef struct OGGPageList {
    OGGPage page;
    struct OGGPageList *next;
} OGGPageList;

typedef struct {
    OGGPageList *page_list;
} OGGContext;

66
static void ogg_update_checksum(AVFormatContext *s, ByteIOContext *pb, int64_t crc_offset)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
67
{
68 69 70 71 72
    int64_t pos = url_ftell(pb);
    uint32_t checksum = get_checksum(pb);
    url_fseek(pb, crc_offset, SEEK_SET);
    put_be32(pb, checksum);
    url_fseek(pb, pos, SEEK_SET);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
73 74
}

75
static int ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
76
{
77
    OGGStreamContext *oggstream = s->streams[page->stream_index]->priv_data;
78
    ByteIOContext *pb;
79
    int64_t crc_offset;
80 81
    int ret, size;
    uint8_t *buf;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
82

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    ret = url_open_dyn_buf(&pb);
    if (ret < 0)
        return ret;
    init_checksum(pb, ff_crc04C11DB7_update, 0);
    put_tag(pb, "OggS");
    put_byte(pb, 0);
    put_byte(pb, page->flags | extra_flags);
    put_le64(pb, page->granule);
    put_le32(pb, oggstream->serial_num);
    put_le32(pb, oggstream->page_counter++);
    crc_offset = url_ftell(pb);
    put_le32(pb, 0); // crc
    put_byte(pb, page->segments_count);
    put_buffer(pb, page->segments, page->segments_count);
    put_buffer(pb, page->data, page->size);

    ogg_update_checksum(s, pb, crc_offset);
    put_flush_packet(pb);

    size = url_close_dyn_buf(pb, &buf);
    if (size < 0)
        return size;

    put_buffer(s->pb, buf, size);
107
    put_flush_packet(s->pb);
108
    oggstream->page_count--;
109
    return 0;
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
}

static int64_t ogg_granule_to_timestamp(OGGStreamContext *oggstream, OGGPage *page)
{
    if (oggstream->kfgshift)
        return (page->granule>>oggstream->kfgshift) +
            (page->granule & ((1<<oggstream->kfgshift)-1));
    else
        return page->granule;
}

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;

    next_granule = av_rescale_q(ogg_granule_to_timestamp(st2->priv_data, next),
                                st2->time_base, AV_TIME_BASE_Q);
    cur_granule  = av_rescale_q(ogg_granule_to_timestamp(st->priv_data, page),
                                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;

    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,
                           uint8_t *data, unsigned size, int64_t granule)
{
    OGGStreamContext *oggstream = st->priv_data;
    int total_segments = size / 255 + 1;
    uint8_t *p = data;
    int i, segments, len;

    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;

        if (page->segments_count == 255) {
            ogg_buffer_page(s, oggstream);
        }
    }
    return 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
205 206
}

207
static uint8_t *ogg_write_vorbiscomment(int offset, int bitexact,
208
                                        int *header_len, AVMetadata *m)
209 210 211 212
{
    const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
    int size;
    uint8_t *p, *p0;
213
    unsigned int count;
214

215
    size = offset + ff_vorbiscomment_length(m, vendor, &count);
216 217 218 219 220 221
    p = av_mallocz(size);
    if (!p)
        return NULL;
    p0 = p;

    p += offset;
222
    ff_vorbiscomment_write(&p, m, vendor, count);
223 224 225 226 227

    *header_len = size;
    return p0;
}

228
static int ogg_build_flac_headers(AVCodecContext *avctx,
229 230
                                  OGGStreamContext *oggstream, int bitexact,
                                  AVMetadata *m)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
231
{
232 233
    enum FLACExtradataFormat format;
    uint8_t *streaminfo;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
234
    uint8_t *p;
235

236
    if (!ff_flac_is_extradata_valid(avctx, &format, &streaminfo))
Baptiste Coudurier's avatar
Baptiste Coudurier committed
237
        return -1;
238 239

    // first packet: STREAMINFO
Justin Ruggles's avatar
Justin Ruggles committed
240 241
    oggstream->header_len[0] = 51;
    oggstream->header[0] = av_mallocz(51); // per ogg flac specs
Baptiste Coudurier's avatar
Baptiste Coudurier committed
242
    p = oggstream->header[0];
243
    if (!p)
244
        return AVERROR(ENOMEM);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
245 246 247 248 249 250 251 252
    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);
253
    bytestream_put_buffer(&p, streaminfo, FLAC_STREAMINFO_SIZE);
254 255

    // second packet: VorbisComment
256
    p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m);
257
    if (!p)
258
        return AVERROR(ENOMEM);
259
    oggstream->header[1] = p;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
260 261
    bytestream_put_byte(&p, 0x84); // last metadata block and vorbis comment
    bytestream_put_be24(&p, oggstream->header_len[1] - 4);
262 263 264 265 266 267 268

    return 0;
}

#define SPEEX_HEADER_SIZE 80

static int ogg_build_speex_headers(AVCodecContext *avctx,
269 270
                                   OGGStreamContext *oggstream, int bitexact,
                                   AVMetadata *m)
271 272 273 274 275 276 277 278 279
{
    uint8_t *p;

    if (avctx->extradata_size < SPEEX_HEADER_SIZE)
        return -1;

    // first packet: Speex header
    p = av_mallocz(SPEEX_HEADER_SIZE);
    if (!p)
280
        return AVERROR(ENOMEM);
281 282 283 284 285 286
    oggstream->header[0] = p;
    oggstream->header_len[0] = SPEEX_HEADER_SIZE;
    bytestream_put_buffer(&p, avctx->extradata, SPEEX_HEADER_SIZE);
    AV_WL32(&oggstream->header[0][68], 0);  // set extra_headers to 0

    // second packet: VorbisComment
287
    p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m);
288
    if (!p)
289
        return AVERROR(ENOMEM);
290
    oggstream->header[1] = p;
291

Baptiste Coudurier's avatar
Baptiste Coudurier committed
292 293 294 295 296 297 298
    return 0;
}

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
300 301
    for (i = 0; i < s->nb_streams; i++) {
        AVStream *st = s->streams[i];
302 303
        unsigned serial_num = i;

304
        if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
305
            av_set_pts_info(st, 64, 1, st->codec->sample_rate);
306
        else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
307 308 309
            av_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
        if (st->codec->codec_id != CODEC_ID_VORBIS &&
            st->codec->codec_id != CODEC_ID_THEORA &&
310
            st->codec->codec_id != CODEC_ID_SPEEX  &&
Baptiste Coudurier's avatar
Baptiste Coudurier committed
311 312 313 314 315 316 317 318 319 320
            st->codec->codec_id != CODEC_ID_FLAC) {
            av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i);
            return -1;
        }

        if (!st->codec->extradata || !st->codec->extradata_size) {
            av_log(s, AV_LOG_ERROR, "No extradata present\n");
            return -1;
        }
        oggstream = av_mallocz(sizeof(*oggstream));
321
        oggstream->page.stream_index = i;
322 323 324 325 326 327 328 329 330 331 332 333

        if (!(st->codec->flags & CODEC_FLAG_BITEXACT))
            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;

Baptiste Coudurier's avatar
Baptiste Coudurier committed
334 335
        st->priv_data = oggstream;
        if (st->codec->codec_id == CODEC_ID_FLAC) {
336
            int err = ogg_build_flac_headers(st->codec, oggstream,
337 338
                                             st->codec->flags & CODEC_FLAG_BITEXACT,
                                             s->metadata);
339
            if (err) {
340
                av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
341
                av_freep(&st->priv_data);
342
                return err;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
343
            }
344 345
        } else if (st->codec->codec_id == CODEC_ID_SPEEX) {
            int err = ogg_build_speex_headers(st->codec, oggstream,
346 347
                                              st->codec->flags & CODEC_FLAG_BITEXACT,
                                              s->metadata);
348 349 350 351 352
            if (err) {
                av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n");
                av_freep(&st->priv_data);
                return err;
            }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
        } else {
            if (ff_split_xiph_headers(st->codec->extradata, st->codec->extradata_size,
                                      st->codec->codec_id == CODEC_ID_VORBIS ? 30 : 42,
                                      oggstream->header, oggstream->header_len) < 0) {
                av_log(s, AV_LOG_ERROR, "Extradata corrupted\n");
                av_freep(&st->priv_data);
                return -1;
            }
            if (st->codec->codec_id == CODEC_ID_THEORA) {
                /** 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);
            }
        }
    }
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385

    for (j = 0; j < s->nb_streams; j++) {
        OGGStreamContext *oggstream = s->streams[j]->priv_data;
        ogg_buffer_data(s, s->streams[j], oggstream->header[0],
                        oggstream->header_len[0], 0);
        oggstream->page.flags |= 2; // bos
        ogg_buffer_page(s, oggstream);
    }
    for (j = 0; j < s->nb_streams; j++) {
        AVStream *st = s->streams[j];
        OGGStreamContext *oggstream = st->priv_data;
        for (i = 1; i < 3; i++) {
            if (oggstream && oggstream->header_len[i])
                ogg_buffer_data(s, st, oggstream->header[i],
                                oggstream->header_len[i], 0);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
386
        }
387
        ogg_buffer_page(s, oggstream);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
388 389 390 391
    }
    return 0;
}

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
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,
                       flush && oggstream->page_count == 1 ? 4 : 0); // eos
        next = p->next;
        av_freep(&p);
        p = next;
    }
    ogg->page_list = p;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
414 415 416 417
static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt)
{
    AVStream *st = s->streams[pkt->stream_index];
    OGGStreamContext *oggstream = st->priv_data;
418
    int ret;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
419 420 421 422 423
    int64_t granule;

    if (st->codec->codec_id == CODEC_ID_THEORA) {
        int64_t pts = oggstream->vrev < 1 ? pkt->pts : pkt->pts + pkt->duration;
        int pframe_count;
424
        if (pkt->flags & AV_PKT_FLAG_KEY)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
425 426 427 428 429 430 431 432 433 434 435
            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;
    } else
        granule = pkt->pts + pkt->duration;

436 437 438
    ret = ogg_buffer_data(s, st, pkt->data, pkt->size, granule);
    if (ret < 0)
        return ret;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
439

440
    ogg_write_pages(s, 0);
441

442
    return 0;
443 444
}

445
static int ogg_write_trailer(AVFormatContext *s)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
446
{
447
    int i;
448

449 450 451
    /* flush current page */
    for (i = 0; i < s->nb_streams; i++)
        ogg_buffer_page(s, s->streams[i]->priv_data);
452

453
    ogg_write_pages(s, 1);
454

Baptiste Coudurier's avatar
Baptiste Coudurier committed
455 456 457
    for (i = 0; i < s->nb_streams; i++) {
        AVStream *st = s->streams[i];
        OGGStreamContext *oggstream = st->priv_data;
458 459
        if (st->codec->codec_id == CODEC_ID_FLAC ||
            st->codec->codec_id == CODEC_ID_SPEEX) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
460 461 462 463 464 465 466 467 468 469
            av_free(oggstream->header[0]);
            av_free(oggstream->header[1]);
        }
        av_freep(&st->priv_data);
    }
    return 0;
}

AVOutputFormat ogg_muxer = {
    "ogg",
470
    NULL_IF_CONFIG_SMALL("Ogg"),
Baptiste Coudurier's avatar
Baptiste Coudurier committed
471
    "application/ogg",
472
    "ogg,ogv,spx",
473
    sizeof(OGGContext),
Baptiste Coudurier's avatar
Baptiste Coudurier committed
474 475 476 477 478
    CODEC_ID_FLAC,
    CODEC_ID_THEORA,
    ogg_write_header,
    ogg_write_packet,
    ogg_write_trailer,
479
    .metadata_conv = ff_vorbiscomment_metadata_conv,
Baptiste Coudurier's avatar
Baptiste Coudurier committed
480
};