diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c index 20245ee43d..cd73df6ad4 100644 --- a/libavformat/flacdec.c +++ b/libavformat/flacdec.c @@ -21,12 +21,127 @@ #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" +static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) +{ + const CodecMime *mime = ff_id3v2_mime_tags; + enum CodecID id = CODEC_ID_NONE; + uint8_t mimetype[64], *desc = NULL, *data = NULL; + AVIOContext *pb = NULL; + AVStream *st; + int type, width, height; + int len, ret = 0; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + 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); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + /* 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"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + mimetype[len] = 0; + + while (mime->id != CODEC_ID_NONE) { + if (!strncmp(mime->str, mimetype, sizeof(mimetype))) { + id = mime->id; + break; + } + mime++; + } + if (id == CODEC_ID_NONE) { + av_log(s, AV_LOG_ERROR, "Unknown attached picture mimetype: %s.\n", + mimetype); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + /* picture description */ + len = avio_rb32(pb); + if (len > 0) { + if (!(desc = av_malloc(len + 1))) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (avio_read(pb, desc, len) != len) { + 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) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + if (!(data = av_malloc(len))) { + ret = AVERROR(ENOMEM); + goto fail; + } + if (avio_read(pb, data, len) != len) { + ret = AVERROR(EIO); + goto fail; + } + + 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; @@ -55,6 +170,7 @@ 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) { @@ -121,6 +237,13 @@ static int flac_read_header(AVFormatContext *s) offset += ti * 12; avpriv_new_chapter(s, track, st->time_base, start, AV_NOPTS_VALUE, isrc); } + } 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) { diff --git a/libavformat/utils.c b/libavformat/utils.c index c0574e521d..6ac12922d5 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -618,7 +618,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma } s->duration = s->start_time = AV_NOPTS_VALUE; - av_strlcpy(s->filename, filename, sizeof(s->filename)); + av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename)); /* allocate private data */ if (s->iformat->priv_data_size > 0) {