• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * WebP encoding support via libwebp
3  * Copyright (c) 2015 Urvang Joshi
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * WebP encoder using libwebp (WebPAnimEncoder API)
25  */
26 
27 #include "config.h"
28 #include "libwebpenc_common.h"
29 
30 #include <webp/mux.h>
31 
32 typedef struct LibWebPAnimContext {
33     LibWebPContextCommon cc;
34     WebPAnimEncoder *enc;     // the main AnimEncoder object
35     int64_t prev_frame_pts;   // pts of the previously encoded frame.
36     int done;                 // If true, we have assembled the bitstream already
37 } LibWebPAnimContext;
38 
libwebp_anim_encode_init(AVCodecContext * avctx)39 static av_cold int libwebp_anim_encode_init(AVCodecContext *avctx)
40 {
41     int ret = ff_libwebp_encode_init_common(avctx);
42     if (!ret) {
43         LibWebPAnimContext *s = avctx->priv_data;
44         WebPAnimEncoderOptions enc_options = { { 0 } };
45         WebPAnimEncoderOptionsInit(&enc_options);
46         enc_options.verbose = av_log_get_level() >= AV_LOG_VERBOSE;
47         // TODO(urvang): Expose some options on command-line perhaps.
48         s->enc = WebPAnimEncoderNew(avctx->width, avctx->height, &enc_options);
49         if (!s->enc)
50             return AVERROR(EINVAL);
51         s->prev_frame_pts = -1;
52         s->done = 0;
53     }
54     return ret;
55 }
56 
libwebp_anim_encode_frame(AVCodecContext * avctx,AVPacket * pkt,const AVFrame * frame,int * got_packet)57 static int libwebp_anim_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
58                                      const AVFrame *frame, int *got_packet) {
59     LibWebPAnimContext *s = avctx->priv_data;
60     int ret;
61 
62     if (!frame) {
63         if (s->done) {  // Second flush: return empty package to denote finish.
64             *got_packet = 0;
65             return 0;
66         } else {  // First flush: assemble bitstream and return it.
67             WebPData assembled_data = { 0 };
68             ret = WebPAnimEncoderAssemble(s->enc, &assembled_data);
69             if (ret) {
70                 ret = ff_alloc_packet2(avctx, pkt, assembled_data.size, assembled_data.size);
71                 if (ret < 0)
72                     return ret;
73                 memcpy(pkt->data, assembled_data.bytes, assembled_data.size);
74                 s->done = 1;
75                 pkt->flags |= AV_PKT_FLAG_KEY;
76                 pkt->pts = pkt->dts = s->prev_frame_pts + 1;
77                 *got_packet = 1;
78                 return 0;
79             } else {
80                 av_log(s, AV_LOG_ERROR,
81                        "WebPAnimEncoderAssemble() failed with error: %d\n",
82                        VP8_ENC_ERROR_OUT_OF_MEMORY);
83                 return AVERROR(ENOMEM);
84             }
85         }
86     } else {
87         int timestamp_ms;
88         WebPPicture *pic = NULL;
89         AVFrame *alt_frame = NULL;
90         ret = ff_libwebp_get_frame(avctx, &s->cc, frame, &alt_frame, &pic);
91         if (ret < 0)
92             goto end;
93 
94         timestamp_ms =
95             avctx->time_base.num * frame->pts * 1000 / avctx->time_base.den;
96         ret = WebPAnimEncoderAdd(s->enc, pic, timestamp_ms, &s->cc.config);
97         if (!ret) {
98                 av_log(avctx, AV_LOG_ERROR,
99                        "Encoding WebP frame failed with error: %d\n",
100                    pic->error_code);
101             ret = ff_libwebp_error_to_averror(pic->error_code);
102             goto end;
103         }
104 
105         pkt->pts = pkt->dts = frame->pts;
106         s->prev_frame_pts = frame->pts;  // Save for next frame.
107         ret = 0;
108         *got_packet = 1;
109 
110 end:
111         WebPPictureFree(pic);
112         av_freep(&pic);
113         av_frame_free(&alt_frame);
114         return ret;
115     }
116 }
117 
libwebp_anim_encode_close(AVCodecContext * avctx)118 static int libwebp_anim_encode_close(AVCodecContext *avctx)
119 {
120     LibWebPAnimContext *s = avctx->priv_data;
121     av_frame_free(&s->cc.ref);
122     WebPAnimEncoderDelete(s->enc);
123 
124     return 0;
125 }
126 
127 static const AVClass class = {
128     .class_name = "libwebp_anim",
129     .item_name  = av_default_item_name,
130     .option     = options,
131     .version    = LIBAVUTIL_VERSION_INT,
132 };
133 
134 AVCodec ff_libwebp_anim_encoder = {
135     .name           = "libwebp_anim",
136     .long_name      = NULL_IF_CONFIG_SMALL("libwebp WebP image"),
137     .type           = AVMEDIA_TYPE_VIDEO,
138     .id             = AV_CODEC_ID_WEBP,
139     .priv_data_size = sizeof(LibWebPAnimContext),
140     .init           = libwebp_anim_encode_init,
141     .encode2        = libwebp_anim_encode_frame,
142     .close          = libwebp_anim_encode_close,
143     .capabilities   = AV_CODEC_CAP_DELAY,
144     .pix_fmts       = (const enum AVPixelFormat[]) {
145         AV_PIX_FMT_RGB32,
146         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
147         AV_PIX_FMT_NONE
148     },
149     .priv_class     = &class,
150     .defaults       = libwebp_defaults,
151     .wrapper_name   = "libwebp",
152 };
153