X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fflacdec.c;h=08bf5388185fe0fcc12e0ea0492be2ddd87d5a63;hb=8672fc7b0453098d862bb1c0caafab4823ee0b4e;hp=20245ee43dc420bcbdebc36e71eb134e281ba9e2;hpb=39de8343f9274f3c93bf44ecb7dcd832b648365d;p=ffmpeg diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c index 20245ee43dc..bbb28f435a4 100644 --- a/libavformat/flacdec.c +++ b/libavformat/flacdec.c @@ -21,12 +21,138 @@ #include "libavcodec/flac.h" #include "avformat.h" +#include "id3v2.h" #include "internal.h" #include "rawdec.h" #include "oggdec.h" #include "vorbiscomment.h" #include "libavcodec/bytestream.h" +#define RETURN_ERROR(code) do { ret = (code); goto fail; } while (0) + +static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) +{ + const CodecMime *mime = ff_id3v2_mime_tags; + enum AVCodecID id = AV_CODEC_ID_NONE; + uint8_t mimetype[64], *desc = NULL, *data = NULL; + AVIOContext *pb = NULL; + AVStream *st; + int type, width, height; + int len, ret = 0; + + pb = avio_alloc_context(buf, buf_size, 0, NULL, NULL, NULL, NULL); + if (!pb) + return AVERROR(ENOMEM); + + /* read the picture type */ + type = avio_rb32(pb); + if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types) || type < 0) { + av_log(s, AV_LOG_ERROR, "Invalid picture type: %d.\n", type); + if (s->error_recognition & AV_EF_EXPLODE) { + RETURN_ERROR(AVERROR_INVALIDDATA); + } + type = 0; + } + + /* picture mimetype */ + len = avio_rb32(pb); + if (len <= 0 || + avio_read(pb, mimetype, FFMIN(len, sizeof(mimetype) - 1)) != len) { + av_log(s, AV_LOG_ERROR, "Could not read mimetype from an attached " + "picture.\n"); + if (s->error_recognition & AV_EF_EXPLODE) + ret = AVERROR_INVALIDDATA; + goto fail; + } + mimetype[len] = 0; + + while (mime->id != AV_CODEC_ID_NONE) { + if (!strncmp(mime->str, mimetype, sizeof(mimetype))) { + id = mime->id; + break; + } + mime++; + } + if (id == AV_CODEC_ID_NONE) { + av_log(s, AV_LOG_ERROR, "Unknown attached picture mimetype: %s.\n", + mimetype); + if (s->error_recognition & AV_EF_EXPLODE) + ret = AVERROR_INVALIDDATA; + goto fail; + } + + /* picture description */ + len = avio_rb32(pb); + if (len > 0) { + if (!(desc = av_malloc(len + 1))) { + RETURN_ERROR(AVERROR(ENOMEM)); + } + + if (avio_read(pb, desc, len) != len) { + av_log(s, AV_LOG_ERROR, "Error reading attached picture description.\n"); + if (s->error_recognition & AV_EF_EXPLODE) + ret = AVERROR(EIO); + goto fail; + } + desc[len] = 0; + } + + /* picture metadata */ + width = avio_rb32(pb); + height = avio_rb32(pb); + avio_skip(pb, 8); + + /* picture data */ + len = avio_rb32(pb); + if (len <= 0) { + av_log(s, AV_LOG_ERROR, "Invalid attached picture size: %d.\n", len); + if (s->error_recognition & AV_EF_EXPLODE) + ret = AVERROR_INVALIDDATA; + goto fail; + } + if (!(data = av_malloc(len))) { + RETURN_ERROR(AVERROR(ENOMEM)); + } + if (avio_read(pb, data, len) != len) { + av_log(s, AV_LOG_ERROR, "Error reading attached picture data.\n"); + if (s->error_recognition & AV_EF_EXPLODE) + ret = AVERROR(EIO); + goto fail; + } + + st = avformat_new_stream(s, NULL); + if (!st) { + RETURN_ERROR(AVERROR(ENOMEM)); + } + + av_init_packet(&st->attached_pic); + st->attached_pic.data = data; + st->attached_pic.size = len; + st->attached_pic.destruct = av_destruct_packet; + st->attached_pic.stream_index = st->index; + st->attached_pic.flags |= AV_PKT_FLAG_KEY; + + st->disposition |= AV_DISPOSITION_ATTACHED_PIC; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = id; + st->codec->width = width; + st->codec->height = height; + av_dict_set(&st->metadata, "comment", ff_id3v2_picture_types[type], 0); + if (desc) + av_dict_set(&st->metadata, "title", desc, AV_DICT_DONT_STRDUP_VAL); + + av_freep(&pb); + + return 0; + +fail: + av_freep(&desc); + av_freep(&data); + av_freep(&pb); + return ret; + +} + static int flac_read_header(AVFormatContext *s) { int ret, metadata_last=0, metadata_type, metadata_size, found_streaminfo=0; @@ -36,8 +162,8 @@ static int flac_read_header(AVFormatContext *s) if (!st) return AVERROR(ENOMEM); st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = CODEC_ID_FLAC; - st->need_parsing = AVSTREAM_PARSE_FULL; + st->codec->codec_id = AV_CODEC_ID_FLAC; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; /* the parameters will be extracted from the compressed bitstream */ /* if fLaC marker is not found, assume there is no header */ @@ -55,14 +181,14 @@ static int flac_read_header(AVFormatContext *s) /* allocate and read metadata block for supported types */ case FLAC_METADATA_TYPE_STREAMINFO: case FLAC_METADATA_TYPE_CUESHEET: + case FLAC_METADATA_TYPE_PICTURE: case FLAC_METADATA_TYPE_VORBIS_COMMENT: buffer = av_mallocz(metadata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (!buffer) { return AVERROR(ENOMEM); } if (avio_read(s->pb, buffer, metadata_size) != metadata_size) { - av_freep(&buffer); - return AVERROR(EIO); + RETURN_ERROR(AVERROR(EIO)); } break; /* skip metadata block for unsupported types */ @@ -76,12 +202,10 @@ static int flac_read_header(AVFormatContext *s) FLACStreaminfo si; /* STREAMINFO can only occur once */ if (found_streaminfo) { - av_freep(&buffer); - return AVERROR_INVALIDDATA; + RETURN_ERROR(AVERROR_INVALIDDATA); } if (metadata_size != FLAC_STREAMINFO_SIZE) { - av_freep(&buffer); - return AVERROR_INVALIDDATA; + RETURN_ERROR(AVERROR_INVALIDDATA); } found_streaminfo = 1; st->codec->extradata = buffer; @@ -103,29 +227,36 @@ static int flac_read_header(AVFormatContext *s) const uint8_t *offset; int i, chapters, track, ti; if (metadata_size < 431) - return AVERROR_INVALIDDATA; + RETURN_ERROR(AVERROR_INVALIDDATA); offset = buffer + 395; chapters = bytestream_get_byte(&offset) - 1; if (chapters <= 0) - return AVERROR_INVALIDDATA; + RETURN_ERROR(AVERROR_INVALIDDATA); for (i = 0; i < chapters; i++) { if (offset + 36 - buffer > metadata_size) - return AVERROR_INVALIDDATA; + RETURN_ERROR(AVERROR_INVALIDDATA); start = bytestream_get_be64(&offset); track = bytestream_get_byte(&offset); bytestream_get_buffer(&offset, isrc, 12); isrc[12] = 0; offset += 14; ti = bytestream_get_byte(&offset); - if (ti <= 0) return AVERROR_INVALIDDATA; + if (ti <= 0) RETURN_ERROR(AVERROR_INVALIDDATA); offset += ti * 12; avpriv_new_chapter(s, track, st->time_base, start, AV_NOPTS_VALUE, isrc); } + av_freep(&buffer); + } else if (metadata_type == FLAC_METADATA_TYPE_PICTURE) { + ret = parse_picture(s, buffer, metadata_size); + av_freep(&buffer); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Error parsing attached picture.\n"); + return ret; + } } else { /* STREAMINFO must be the first block */ if (!found_streaminfo) { - av_freep(&buffer); - return AVERROR_INVALIDDATA; + RETURN_ERROR(AVERROR_INVALIDDATA); } /* process supported blocks other than STREAMINFO */ if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) { @@ -138,6 +269,10 @@ static int flac_read_header(AVFormatContext *s) } return 0; + +fail: + av_free(buffer); + return ret; } static int flac_probe(AVProbeData *p) @@ -157,5 +292,5 @@ AVInputFormat ff_flac_demuxer = { .read_packet = ff_raw_read_partial_packet, .flags = AVFMT_GENERIC_INDEX, .extensions = "flac", - .raw_codec_id = CODEC_ID_FLAC, + .raw_codec_id = AV_CODEC_ID_FLAC, };