Skip to content

Instantly share code, notes, and snippets.

@blluv
Created July 21, 2022 14:21
Show Gist options
  • Save blluv/5bf3dfdd4aa30f0c8cee65f8c628c3a3 to your computer and use it in GitHub Desktop.
Save blluv/5bf3dfdd4aa30f0c8cee65f8c628c3a3 to your computer and use it in GitHub Desktop.
webp2webm
#include <webp/decode.h>
#include <webp/demux.h>
#include <fstream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/opt.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
static void encode_frame(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
AVFormatContext *outCtx, AVStream *stream) {
int ret;
/* send the frame to the encoder */
ret = avcodec_send_frame(enc_ctx, frame);
if (ret < 0) {
fprintf(stderr, "error sending a frame for encoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_packet(enc_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "error during encoding\n");
exit(1);
}
av_packet_rescale_ts(pkt, enc_ctx->time_base, stream->time_base);
av_write_frame(outCtx, pkt);
av_packet_unref(pkt);
}
}
int main() {
av_log_set_level(AV_LOG_DEBUG);
std::streamsize length;
char *buffer;
std::ifstream is;
is.open("../emot_002.webp", std::ios::binary);
is.seekg(0, std::ios::end);
length = is.tellg();
is.seekg(0, std::ios::beg);
buffer = new char[length];
is.read(buffer, length);
is.close();
WebPData data;
data.bytes = (uint8_t *) buffer;
data.size = length;
// decoder
auto demux = WebPDemux(&data);
uint32_t webp_width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
uint32_t webp_height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
WebPAnimDecoderOptions dec_options;
WebPAnimDecoderOptionsInit(&dec_options);
dec_options.color_mode = WEBP_CSP_MODE::MODE_RGBA;
WebPAnimDecoder *dec = WebPAnimDecoderNew(&data, &dec_options);
WebPAnimInfo anim_info;
WebPAnimDecoderGetInfo(dec, &anim_info);
const AVCodec *codec;
AVCodecContext *ctx;
codec = avcodec_find_encoder(AV_CODEC_ID_VP9);
if (!codec) {
printf("codec not found\n");
exit(1);
}
ctx = avcodec_alloc_context3(codec);
ctx->width = 512;
ctx->height = 512;
ctx->pix_fmt = AV_PIX_FMT_YUVA420P;
ctx->time_base = AVRational{1, 12};
ctx->bit_rate = 512 * 512 * 4;
if (avcodec_open2(ctx, codec, nullptr) < 0) {
printf("couldn't open codec\n");
exit(1);
}
AVFrame *picture;
picture = av_frame_alloc();
picture->width = 512;
picture->height = 512;
picture->format = AV_PIX_FMT_YUVA420P;
av_frame_get_buffer(picture, 1);
AVFrame *origPicture;
origPicture = av_frame_alloc();
origPicture->width = webp_width;
origPicture->height = webp_height;
origPicture->format = AV_PIX_FMT_RGBA;
av_frame_get_buffer(origPicture, 1);
av_frame_make_writable(picture);
av_frame_make_writable(origPicture);
auto sws = sws_getContext(
webp_width, webp_height, AV_PIX_FMT_RGBA,
512, 512, AV_PIX_FMT_YUVA420P,
SWS_BILINEAR, nullptr, nullptr, nullptr);
const AVOutputFormat *outFmt = av_guess_format("webm", nullptr, nullptr);
AVFormatContext *outCtx;
avformat_alloc_output_context2(&outCtx, outFmt, nullptr, nullptr);
AVStream *stream;
stream = avformat_new_stream(outCtx, nullptr);
stream->codecpar->codec_id = AV_CODEC_ID_VP9;
stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
stream->codecpar->width = 512;
stream->codecpar->height = 512;
stream->codecpar->format = AV_PIX_FMT_YUVA420P;
stream->time_base = AVRational{1, 1};
avio_open(&outCtx->pb, "../testttttt.webm", AVIO_FLAG_WRITE);
avformat_write_header(outCtx, nullptr);
AVPacket *pkt = av_packet_alloc();
int timestamp;
int frame_count = 0;
while (WebPAnimDecoderHasMoreFrames(dec)) {
uint8_t *buf;
WebPAnimDecoderGetNext(dec, &buf, &timestamp);
av_image_fill_arrays(origPicture->data, origPicture->linesize, buf,
AV_PIX_FMT_RGBA,
webp_width, webp_height, 1);
sws_scale(sws, origPicture->data, origPicture->linesize, 0,
origPicture->height, picture->data, picture->linesize);
picture->pts = frame_count;
encode_frame(ctx, picture, pkt, outCtx, stream);
frame_count++;
}
WebPAnimDecoderDelete(dec);
encode_frame(ctx, nullptr, pkt, outCtx, stream);
av_write_trailer(outCtx);
avio_close(outCtx->pb);
avformat_free_context(outCtx);
av_frame_free(&picture);
av_packet_free(&pkt);
avcodec_close(ctx);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment