Up until now ff_vorbiscomment_write() used the bytestream API to write VorbisComments. Therefore the caller had to provide a sufficiently large buffer to write the output. Yet two of the three callers (namely the FLAC and the Matroska muxer) actually want the output to be written via an AVIOContext; therefore they allocated buffers of the right size just for this purpose (i.e. they get freed immediately afterwards). Only the Ogg muxer actually wants a buffer. But given that it is easy to wrap a buffer into an AVIOContext this commit changes ff_vorbiscomment_write() to use an AVIOContext for its output. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>tags/n4.3
| @@ -29,7 +29,6 @@ | |||
| #include "id3v2.h" | |||
| #include "internal.h" | |||
| #include "vorbiscomment.h" | |||
| #include "libavcodec/bytestream.h" | |||
| typedef struct FlacMuxerContext { | |||
| @@ -62,25 +61,16 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m, | |||
| { | |||
| const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; | |||
| int64_t len; | |||
| uint8_t *p, *p0; | |||
| ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL); | |||
| len = ff_vorbiscomment_length(*m, vendor, NULL, 0); | |||
| if (len >= ((1<<24) - 4)) | |||
| return AVERROR(EINVAL); | |||
| p0 = av_malloc(len+4); | |||
| if (!p0) | |||
| return AVERROR(ENOMEM); | |||
| p = p0; | |||
| bytestream_put_byte(&p, last_block ? 0x84 : 0x04); | |||
| bytestream_put_be24(&p, len); | |||
| ff_vorbiscomment_write(&p, *m, vendor, NULL, 0); | |||
| avio_write(pb, p0, len+4); | |||
| av_freep(&p0); | |||
| p = NULL; | |||
| avio_w8(pb, last_block ? 0x84 : 0x04); | |||
| avio_wb24(pb, len); | |||
| ff_vorbiscomment_write(pb, *m, vendor, NULL, 0); | |||
| return 0; | |||
| } | |||
| @@ -624,7 +624,7 @@ static int put_flac_codecpriv(AVFormatContext *s, AVIOContext *pb, | |||
| const char *vendor = (s->flags & AVFMT_FLAG_BITEXACT) ? | |||
| "Lavf" : LIBAVFORMAT_IDENT; | |||
| AVDictionary *dict = NULL; | |||
| uint8_t buf[32], *data, *p; | |||
| uint8_t buf[32]; | |||
| int64_t len; | |||
| snprintf(buf, sizeof(buf), "0x%"PRIx64, par->channel_layout); | |||
| @@ -633,21 +633,11 @@ static int put_flac_codecpriv(AVFormatContext *s, AVIOContext *pb, | |||
| len = ff_vorbiscomment_length(dict, vendor, NULL, 0); | |||
| av_assert1(len < (1 << 24) - 4); | |||
| data = av_malloc(len + 4); | |||
| if (!data) { | |||
| av_dict_free(&dict); | |||
| return AVERROR(ENOMEM); | |||
| } | |||
| data[0] = 0x84; | |||
| AV_WB24(data + 1, len); | |||
| p = data + 4; | |||
| ff_vorbiscomment_write(&p, dict, vendor, NULL, 0); | |||
| avio_w8(pb, 0x84); | |||
| avio_wb24(pb, len); | |||
| avio_write(pb, data, len + 4); | |||
| ff_vorbiscomment_write(pb, dict, vendor, NULL, 0); | |||
| av_freep(&data); | |||
| av_dict_free(&dict); | |||
| } | |||
| @@ -294,8 +294,9 @@ static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, | |||
| 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); | |||
| @@ -305,15 +306,14 @@ static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, | |||
| p = av_mallocz(size); | |||
| if (!p) | |||
| return NULL; | |||
| p0 = p; | |||
| p += offset; | |||
| ff_vorbiscomment_write(&p, *m, vendor, chapters, nb_chapters); | |||
| 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, | |||
| @@ -19,10 +19,10 @@ | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "avio.h" | |||
| #include "avformat.h" | |||
| #include "metadata.h" | |||
| #include "vorbiscomment.h" | |||
| #include "libavcodec/bytestream.h" | |||
| #include "libavutil/dict.h" | |||
| /** | |||
| @@ -62,13 +62,13 @@ int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string | |||
| return len; | |||
| } | |||
| int ff_vorbiscomment_write(uint8_t **p, const AVDictionary *m, | |||
| int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m, | |||
| const char *vendor_string, | |||
| AVChapter **chapters, unsigned int nb_chapters) | |||
| { | |||
| int cm_count = 0; | |||
| bytestream_put_le32(p, strlen(vendor_string)); | |||
| bytestream_put_buffer(p, vendor_string, strlen(vendor_string)); | |||
| avio_wl32(pb, strlen(vendor_string)); | |||
| avio_write(pb, vendor_string, strlen(vendor_string)); | |||
| if (chapters && nb_chapters) { | |||
| for (int i = 0; i < nb_chapters; i++) { | |||
| cm_count += av_dict_count(chapters[i]->metadata) + 1; | |||
| @@ -77,16 +77,16 @@ int ff_vorbiscomment_write(uint8_t **p, const AVDictionary *m, | |||
| if (m) { | |||
| int count = av_dict_count(m) + cm_count; | |||
| AVDictionaryEntry *tag = NULL; | |||
| bytestream_put_le32(p, count); | |||
| avio_wl32(pb, count); | |||
| while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) { | |||
| int64_t len1 = strlen(tag->key); | |||
| int64_t len2 = strlen(tag->value); | |||
| if (len1+1+len2 > UINT32_MAX) | |||
| return AVERROR(EINVAL); | |||
| bytestream_put_le32(p, len1+1+len2); | |||
| bytestream_put_buffer(p, tag->key, len1); | |||
| bytestream_put_byte(p, '='); | |||
| bytestream_put_buffer(p, tag->value, len2); | |||
| avio_wl32(pb, len1 + 1 + len2); | |||
| avio_write(pb, tag->key, len1); | |||
| avio_w8(pb, '='); | |||
| avio_write(pb, tag->value, len2); | |||
| } | |||
| for (int i = 0; i < nb_chapters; i++) { | |||
| AVChapter *chp = chapters[i]; | |||
| @@ -101,11 +101,11 @@ int ff_vorbiscomment_write(uint8_t **p, const AVDictionary *m, | |||
| s = s % 60; | |||
| snprintf(chapter_number, sizeof(chapter_number), "%03d", i); | |||
| snprintf(chapter_time, sizeof(chapter_time), "%02d:%02d:%02d.%03d", h, m, s, ms); | |||
| bytestream_put_le32(p, 10+1+12); | |||
| bytestream_put_buffer(p, "CHAPTER", 7); | |||
| bytestream_put_buffer(p, chapter_number, 3); | |||
| bytestream_put_byte(p, '='); | |||
| bytestream_put_buffer(p, chapter_time, 12); | |||
| avio_wl32(pb, 10 + 1 + 12); | |||
| avio_write(pb, "CHAPTER", 7); | |||
| avio_write(pb, chapter_number, 3); | |||
| avio_w8(pb, '='); | |||
| avio_write(pb, chapter_time, 12); | |||
| tag = NULL; | |||
| while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { | |||
| @@ -113,18 +113,18 @@ int ff_vorbiscomment_write(uint8_t **p, const AVDictionary *m, | |||
| int64_t len2 = strlen(tag->value); | |||
| if (len1+1+len2+10 > UINT32_MAX) | |||
| return AVERROR(EINVAL); | |||
| bytestream_put_le32(p, 10+len1+1+len2); | |||
| bytestream_put_buffer(p, "CHAPTER", 7); | |||
| bytestream_put_buffer(p, chapter_number, 3); | |||
| avio_wl32(pb, 10 + len1 + 1 + len2); | |||
| avio_write(pb, "CHAPTER", 7); | |||
| avio_write(pb, chapter_number, 3); | |||
| if (!strcmp(tag->key, "title")) | |||
| bytestream_put_buffer(p, "NAME", 4); | |||
| avio_write(pb, "NAME", 4); | |||
| else | |||
| bytestream_put_buffer(p, tag->key, len1); | |||
| bytestream_put_byte(p, '='); | |||
| bytestream_put_buffer(p, tag->value, len2); | |||
| avio_write(pb, tag->key, len1); | |||
| avio_w8(pb, '='); | |||
| avio_write(pb, tag->value, len2); | |||
| } | |||
| } | |||
| } else | |||
| bytestream_put_le32(p, 0); | |||
| avio_wl32(pb, 0); | |||
| return 0; | |||
| } | |||
| @@ -38,18 +38,17 @@ int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string | |||
| AVChapter **chapters, unsigned int nb_chapters); | |||
| /** | |||
| * Write a VorbisComment into a buffer. The buffer, p, must have enough | |||
| * data to hold the whole VorbisComment. The minimum size required can be | |||
| * obtained by passing the same AVDictionary and vendor_string to | |||
| * Write a VorbisComment into an AVIOContext. The output size can be obtained | |||
| * in advance by passing the same chapters, AVDictionary and vendor_string to | |||
| * ff_vorbiscomment_length() | |||
| * | |||
| * @param p The buffer in which to write. | |||
| * @param pb The AVIOContext to write the output. | |||
| * @param m The metadata struct to write. | |||
| * @param vendor_string The vendor string to write. | |||
| * @param chapters The chapters to write. | |||
| * @param nb_chapters The number of chapters to write. | |||
| */ | |||
| int ff_vorbiscomment_write(uint8_t **p, const AVDictionary *m, | |||
| int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m, | |||
| const char *vendor_string, | |||
| AVChapter **chapters, unsigned int nb_chapters); | |||