Created
July 21, 2022 14:21
-
-
Save blluv/5bf3dfdd4aa30f0c8cee65f8c628c3a3 to your computer and use it in GitHub Desktop.
webp2webm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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, ×tamp); | |
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