X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Foggenc.c;h=f5032759a649f137b725e265cd6507b391c8b75c;hb=ef6a9e5e311f09fa8032974fa4d0c1e166a959bb;hp=10c4eda06212cc204cd7a00418a61e1170f1a052;hpb=203bbaccfaaeac9548862e83792d38509a8c8167;p=ffmpeg diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index 10c4eda0621..f5032759a64 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -99,51 +99,32 @@ static const AVClass flavor ## _muxer_class = {\ .version = LIBAVUTIL_VERSION_INT,\ }; -static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset) -{ - int64_t pos = avio_tell(pb); - uint32_t checksum = ffio_get_checksum(pb); - avio_seek(pb, crc_offset, SEEK_SET); - avio_wb32(pb, checksum); - avio_seek(pb, pos, SEEK_SET); -} - -static int ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) +static void ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) { OGGStreamContext *oggstream = s->streams[page->stream_index]->priv_data; - AVIOContext *pb; - int64_t crc_offset; - int ret, size; - uint8_t *buf; - - ret = avio_open_dyn_buf(&pb); - if (ret < 0) - return ret; - ffio_init_checksum(pb, ff_crc04C11DB7_update, 0); - ffio_wfourcc(pb, "OggS"); - 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++); - crc_offset = avio_tell(pb); - 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); - - ogg_update_checksum(s, pb, crc_offset); - avio_flush(pb); - - size = avio_close_dyn_buf(pb, &buf); - if (size < 0) - return size; - - avio_write(s->pb, buf, size); - avio_flush(s->pb); - av_free(buf); + uint8_t buf[4 + 1 + 1 + 8 + 4 + 4 + 4 + 1 + 255], *ptr = buf, *crc_pos; + const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE); + uint32_t crc; + + bytestream_put_le32(&ptr, MKTAG('O', 'g', 'g', 'S')); + bytestream_put_byte(&ptr, 0); + bytestream_put_byte(&ptr, page->flags | extra_flags); + bytestream_put_le64(&ptr, page->granule); + bytestream_put_le32(&ptr, oggstream->serial_num); + bytestream_put_le32(&ptr, oggstream->page_counter++); + crc_pos = ptr; + bytestream_put_le32(&ptr, 0); + bytestream_put_byte(&ptr, page->segments_count); + bytestream_put_buffer(&ptr, page->segments, page->segments_count); + + crc = av_crc(crc_table, 0, buf, ptr - buf); + crc = av_crc(crc_table, crc, page->data, page->size); + bytestream_put_be32(&crc_pos, crc); + + avio_write(s->pb, buf, ptr - buf); + avio_write(s->pb, page->data, page->size); + avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); oggstream->page_count--; - return 0; } static int ogg_key_granule(OGGStreamContext *oggstream, int64_t granule) @@ -291,29 +272,30 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, } static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, - int *header_len, AVDictionary **m, int framing_bit) + int *header_len, AVDictionary **m, int framing_bit, + AVChapter **chapters, unsigned int nb_chapters) { const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; + AVIOContext pb; int64_t size; - uint8_t *p, *p0; + uint8_t *p; ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL); - size = offset + ff_vorbiscomment_length(*m, vendor) + framing_bit; + size = offset + ff_vorbiscomment_length(*m, vendor, chapters, nb_chapters) + framing_bit; if (size > INT_MAX) return NULL; p = av_mallocz(size); if (!p) return NULL; - p0 = p; - p += offset; - ff_vorbiscomment_write(&p, m, vendor); + ffio_init_context(&pb, p + offset, size - offset, 1, NULL, NULL, NULL, NULL); + ff_vorbiscomment_write(&pb, *m, vendor, chapters, nb_chapters); if (framing_bit) - bytestream_put_byte(&p, 1); + avio_w8(&pb, 1); *header_len = size; - return p0; + return p; } static int ogg_build_flac_headers(AVCodecParameters *par, @@ -342,7 +324,7 @@ static int ogg_build_flac_headers(AVCodecParameters *par, bytestream_put_buffer(&p, par->extradata, FLAC_STREAMINFO_SIZE); // second packet: VorbisComment - p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m, 0); + p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m, 0, NULL, 0); if (!p) return AVERROR(ENOMEM); oggstream->header[1] = p; @@ -373,7 +355,7 @@ static int ogg_build_speex_headers(AVCodecParameters *par, AV_WL32(&oggstream->header[0][68], 0); // set extra_headers to 0 // second packet: VorbisComment - p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0); + p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0, NULL, 0); if (!p) return AVERROR(ENOMEM); oggstream->header[1] = p; @@ -385,7 +367,8 @@ static int ogg_build_speex_headers(AVCodecParameters *par, static int ogg_build_opus_headers(AVCodecParameters *par, OGGStreamContext *oggstream, int bitexact, - AVDictionary **m) + AVDictionary **m, AVChapter **chapters, + unsigned int nb_chapters) { uint8_t *p; @@ -401,7 +384,7 @@ static int ogg_build_opus_headers(AVCodecParameters *par, bytestream_put_buffer(&p, par->extradata, par->extradata_size); /* second packet: VorbisComment */ - p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0); + p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0, chapters, nb_chapters); if (!p) return AVERROR(ENOMEM); oggstream->header[1] = p; @@ -446,7 +429,7 @@ static int ogg_build_vp8_headers(AVFormatContext *s, AVStream *st, /* optional second packet: VorbisComment */ if (av_dict_get(st->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) { - p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0); + p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0, NULL, 0); if (!p) return AVERROR(ENOMEM); oggstream->header[1] = p; @@ -545,7 +528,6 @@ static int ogg_init(AVFormatContext *s) &st->metadata); if (err) { av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n"); - av_freep(&st->priv_data); return err; } } else if (st->codecpar->codec_id == AV_CODEC_ID_SPEEX) { @@ -554,16 +536,14 @@ static int ogg_init(AVFormatContext *s) &st->metadata); if (err) { av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n"); - av_freep(&st->priv_data); return err; } } else if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) { int err = ogg_build_opus_headers(st->codecpar, oggstream, s->flags & AVFMT_FLAG_BITEXACT, - &st->metadata); + &st->metadata, s->chapters, s->nb_chapters); if (err) { av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n"); - av_freep(&st->priv_data); return err; } } else if (st->codecpar->codec_id == AV_CODEC_ID_VP8) { @@ -571,7 +551,6 @@ static int ogg_init(AVFormatContext *s) 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; } } else { @@ -584,13 +563,13 @@ static int ogg_init(AVFormatContext *s) st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? 30 : 42, (const uint8_t**)oggstream->header, oggstream->header_len) < 0) { av_log(s, AV_LOG_ERROR, "Extradata corrupted\n"); - av_freep(&st->priv_data); + oggstream->header[1] = NULL; return AVERROR_INVALIDDATA; } p = ogg_write_vorbiscomment(7, s->flags & AVFMT_FLAG_BITEXACT, &oggstream->header_len[1], &st->metadata, - framing_bit); + framing_bit, NULL, 0); oggstream->header[1] = p; if (!p) return AVERROR(ENOMEM); @@ -738,6 +717,8 @@ static int ogg_write_trailer(AVFormatContext *s) static void ogg_free(AVFormatContext *s) { + OGGContext *ogg = s->priv_data; + OGGPageList *p = ogg->page_list; int i; for (i = 0; i < s->nb_streams; i++) { @@ -752,8 +733,14 @@ static void ogg_free(AVFormatContext *s) av_freep(&oggstream->header[0]); } av_freep(&oggstream->header[1]); - av_freep(&st->priv_data); } + + while (p) { + OGGPageList *next = p->next; + av_free(p); + p = next; + } + ogg->page_list = NULL; } #if CONFIG_OGG_MUXER