blob: b15950ade5d75d333b9f4ee031429ca26ea57d0a [file] [log] [blame]
/*
* Copyright (c) 2010, Google, Inc.
*
* 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
*/
/*
* @file
* WebP demuxer
* http://code.google.com/p/webp
*
* supports metadata: artist, copyright, title, comment
* Encoding/decoding examples:
* ffmpeg -i my_image
* -metadata artist=me -metadata title="sunset"
* -metadata copyright=2010 -metadata comment="nice pic!"
* -profile 1 -qmin 5 my_image.webp
* ffmpeg -i my_image.webp -y my_image.png
*/
#include "webp.h"
#include "libavutil/intreadwrite.h"
static const AVCodecTag webp_codec_tags[] = {
{ CODEC_ID_VP8, MKTAG('V', 'P', '8', ' ') },
{ CODEC_ID_NONE, 0 }
};
static int probe(AVProbeData *p)
{
if (!memcmp(p->buf, "RIFF", 4) && !memcmp(p->buf + 8, "WEBP", 4))
return AVPROBE_SCORE_MAX;
return 0;
}
static int read_header(AVFormatContext *s, AVFormatParameters *ap)
{
AVStream *st;
uint32_t riff_size;
if (get_le32(s->pb) != AV_RL32("RIFF"))
return AVERROR(EINVAL);
riff_size = get_le32(s->pb);
if (get_le32(s->pb) != AV_RL32("WEBP"))
return AVERROR(EINVAL);
st = av_new_stream(s, 0);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_tag = AV_RL32("VP8 ");
st->codec->codec_id = ff_codec_get_id(webp_codec_tags,
st->codec->codec_tag);
av_set_pts_info(st, 24, 1, 1000);
return 0;
}
static int set_metadata(ByteIOContext* pb, AVMetadata** metadata,
const char* generic_key, uint32_t size)
{
char* const value = av_malloc(size + 1);
if (!value)
return AVERROR(ENOMEM);
if (get_buffer(pb, value, size) < 0)
return AVERROR(EINVAL);
value[size] = 0;
if (av_metadata_set2(metadata, generic_key, value, 0))
return AVERROR(EINVAL);
av_free(value);
return size;
}
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret = -1;
AVStream *stream = s->streams[pkt->stream_index];
uint32_t tag = get_le32(s->pb);
uint32_t chunk_size = get_le32(s->pb);
if (tag == stream->codec->codec_tag) {
ret = av_get_packet(s->pb, pkt, chunk_size);
pkt->flags |= AV_PKT_FLAG_KEY;
}
else {
int i;
for (i = 0; ff_webp_metadata_conv[i].native; ++i) {
const char* native_tag = ff_webp_metadata_conv[i].native;
if (tag == AV_RL32(native_tag)) {
ret = set_metadata(s->pb, &stream->metadata,
ff_webp_metadata_conv[i].generic,
chunk_size);
break;
}
}
}
return ret;
}
static int read_close(struct AVFormatContext *s)
{
return 0;
}
AVInputFormat webp_demuxer = {
.name = "webp",
.long_name = NULL_IF_CONFIG_SMALL("WebP"),
.priv_data_size = 0,
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
.read_close = read_close,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "webp",
.value = CODEC_ID_VP8,
.codec_tag = (const AVCodecTag*[]){webp_codec_tags, 0},
};