You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
4.9KB

  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. * @file
  23. * WebP encoder using libwebp (WebPAnimEncoder API)
  24. */
  25. #include "config.h"
  26. #include "libwebpenc_common.h"
  27. #if HAVE_WEBP_MUX_H
  28. #include <webp/mux.h>
  29. #endif
  30. typedef struct LibWebPAnimContext {
  31. LibWebPContextCommon cc;
  32. WebPAnimEncoder *enc; // the main AnimEncoder object
  33. int64_t prev_frame_pts; // pts of the previously encoded frame.
  34. int done; // If true, we have assembled the bitstream already
  35. } LibWebPAnimContext;
  36. static av_cold int libwebp_anim_encode_init(AVCodecContext *avctx)
  37. {
  38. int ret = ff_libwebp_encode_init_common(avctx);
  39. if (!ret) {
  40. LibWebPAnimContext *s = avctx->priv_data;
  41. WebPAnimEncoderOptions enc_options;
  42. WebPAnimEncoderOptionsInit(&enc_options);
  43. // TODO(urvang): Expose some options on command-line perhaps.
  44. s->enc = WebPAnimEncoderNew(avctx->width, avctx->height, &enc_options);
  45. if (!s->enc)
  46. return AVERROR(EINVAL);
  47. s->prev_frame_pts = -1;
  48. s->done = 0;
  49. }
  50. return ret;
  51. }
  52. static int libwebp_anim_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
  53. const AVFrame *frame, int *got_packet) {
  54. LibWebPAnimContext *s = avctx->priv_data;
  55. int ret;
  56. if (!frame) {
  57. if (s->done) { // Second flush: return empty package to denote finish.
  58. *got_packet = 0;
  59. return 0;
  60. } else { // First flush: assemble bitstream and return it.
  61. WebPData assembled_data = { 0 };
  62. ret = WebPAnimEncoderAssemble(s->enc, &assembled_data);
  63. if (ret) {
  64. ret = ff_alloc_packet(pkt, assembled_data.size);
  65. if (ret < 0)
  66. return ret;
  67. memcpy(pkt->data, assembled_data.bytes, assembled_data.size);
  68. s->done = 1;
  69. pkt->flags |= AV_PKT_FLAG_KEY;
  70. pkt->pts = pkt->dts = s->prev_frame_pts + 1;
  71. *got_packet = 1;
  72. return 0;
  73. } else {
  74. av_log(s, AV_LOG_ERROR,
  75. "WebPAnimEncoderAssemble() failed with error: %d\n",
  76. VP8_ENC_ERROR_OUT_OF_MEMORY);
  77. return AVERROR(ENOMEM);
  78. }
  79. }
  80. } else {
  81. int timestamp_ms;
  82. WebPPicture *pic = NULL;
  83. AVFrame *alt_frame = NULL;
  84. ret = ff_libwebp_get_frame(avctx, &s->cc, frame, &alt_frame, &pic);
  85. if (ret < 0)
  86. goto end;
  87. timestamp_ms =
  88. avctx->time_base.num * frame->pts * 1000 / avctx->time_base.den;
  89. ret = WebPAnimEncoderAdd(s->enc, pic, timestamp_ms, &s->cc.config);
  90. if (!ret) {
  91. av_log(avctx, AV_LOG_ERROR,
  92. "Encoding WebP frame failed with error: %d\n",
  93. pic->error_code);
  94. ret = ff_libwebp_error_to_averror(pic->error_code);
  95. goto end;
  96. }
  97. pkt->pts = pkt->dts = frame->pts;
  98. s->prev_frame_pts = frame->pts; // Save for next frame.
  99. ret = 0;
  100. *got_packet = 1;
  101. end:
  102. WebPPictureFree(pic);
  103. av_freep(&pic);
  104. av_frame_free(&alt_frame);
  105. return ret;
  106. }
  107. }
  108. static int libwebp_anim_encode_close(AVCodecContext *avctx)
  109. {
  110. int ret = ff_libwebp_encode_close_common(avctx);
  111. if (!ret) {
  112. LibWebPAnimContext *s = avctx->priv_data;
  113. WebPAnimEncoderDelete(s->enc);
  114. }
  115. return ret;
  116. }
  117. AVCodec ff_libwebp_anim_encoder = {
  118. .name = "libwebp_anim",
  119. .long_name = NULL_IF_CONFIG_SMALL("libwebp WebP image"),
  120. .type = AVMEDIA_TYPE_VIDEO,
  121. .id = AV_CODEC_ID_WEBP,
  122. .priv_data_size = sizeof(LibWebPAnimContext),
  123. .init = libwebp_anim_encode_init,
  124. .encode2 = libwebp_anim_encode_frame,
  125. .close = libwebp_anim_encode_close,
  126. .capabilities = CODEC_CAP_DELAY,
  127. .pix_fmts = (const enum AVPixelFormat[]) {
  128. AV_PIX_FMT_RGB32,
  129. AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
  130. AV_PIX_FMT_NONE
  131. },
  132. .priv_class = &class,
  133. .defaults = libwebp_defaults,
  134. };