static void write_thumb(const AVCodecContext *src, const AVFrame *sframe, int width, int height, const char *cacheid, time_t mtime) { if(thumbcodec == NULL) return; AVCodecContext *ctx = thumbctx; if(ctx == NULL || ctx->width != width || ctx->height != height) { if(ctx != NULL) { avcodec_close(ctx); free(ctx); } ctx = avcodec_alloc_context3(thumbcodec); ctx->pix_fmt = AV_PIX_FMT_YUVJ420P; ctx->time_base.den = 1; ctx->time_base.num = 1; ctx->sample_aspect_ratio.num = 1; ctx->sample_aspect_ratio.den = 1; ctx->width = width; ctx->height = height; if(avcodec_open2(ctx, thumbcodec, NULL) < 0) { TRACE(TRACE_ERROR, "THUMB", "Unable to open thumb encoder"); thumbctx = NULL; return; } thumbctx = ctx; } AVFrame *oframe = av_frame_alloc(); avpicture_alloc((AVPicture *)oframe, ctx->pix_fmt, width, height); struct SwsContext *sws; sws = sws_getContext(src->width, src->height, src->pix_fmt, width, height, ctx->pix_fmt, SWS_BILINEAR, NULL, NULL, NULL); sws_scale(sws, (const uint8_t **)sframe->data, sframe->linesize, 0, src->height, &oframe->data[0], &oframe->linesize[0]); sws_freeContext(sws); oframe->pts = AV_NOPTS_VALUE; AVPacket out; memset(&out, 0, sizeof(AVPacket)); int got_packet; int r = avcodec_encode_video2(ctx, &out, oframe, &got_packet); if(r >= 0 && got_packet) { buf_t *b = buf_create_and_adopt(out.size, out.data, &av_free); blobcache_put(cacheid, "videothumb", b, INT32_MAX, NULL, mtime, 0); buf_release(b); } else { assert(out.data == NULL); } av_frame_free(&oframe); }
static buf_t * screenshot_compress(pixmap_t *pm, int codecid) { AVCodec *codec = avcodec_find_encoder(codecid); if(codec == NULL) return NULL; const int width = pm->pm_width; const int height = pm->pm_height; AVCodecContext *ctx = avcodec_alloc_context3(codec); ctx->pix_fmt = codec->pix_fmts[0]; ctx->time_base.den = 1; ctx->time_base.num = 1; ctx->sample_aspect_ratio.num = 1; ctx->sample_aspect_ratio.den = 1; ctx->width = width; ctx->height = height; if(avcodec_open2(ctx, codec, NULL) < 0) { TRACE(TRACE_ERROR, "ScreenShot", "Unable to open image encoder"); return NULL; } AVFrame *oframe = av_frame_alloc(); avpicture_alloc((AVPicture *)oframe, ctx->pix_fmt, width, height); const uint8_t *ptr[4] = {pm->pm_data + pm->pm_linesize * (height - 1)}; int strides[4] = {-pm->pm_linesize}; struct SwsContext *sws; sws = sws_getContext(width, height, PIX_FMT_RGB32, width, height, ctx->pix_fmt, SWS_BILINEAR, NULL, NULL, NULL); sws_scale(sws, ptr, strides, 0, height, &oframe->data[0], &oframe->linesize[0]); sws_freeContext(sws); oframe->pts = AV_NOPTS_VALUE; AVPacket out; memset(&out, 0, sizeof(AVPacket)); int got_packet; int r = avcodec_encode_video2(ctx, &out, oframe, &got_packet); buf_t *b; if(r >= 0 && got_packet) { b = buf_create_and_adopt(out.size, out.data, &av_free); } else { assert(out.data == NULL); b = NULL; } av_frame_free(&oframe); avcodec_close(ctx); av_free(ctx); return b; }
buf_t * gz_inflate(buf_t *bin, char *errbuf, size_t errlen) { z_stream z = {0}; unsigned char *out; size_t outlen; int r; if(!gz_check(bin)) { snprintf(errbuf, errlen, "Invalid header"); buf_release(bin); return NULL; } const uint8_t *in = buf_c8(bin); size_t inlen = bin->b_size; if(in[3] != 0) { snprintf(errbuf, errlen, "Header extensions is not supported"); buf_release(bin); return NULL; } in += 10; inlen -= 10; z.next_in = (void *)in; z.avail_in = inlen; if(inflateInit2(&z, -MAX_WBITS) != Z_OK) { snprintf(errbuf, errlen, "Inflate init failed"); buf_release(bin); return NULL; } outlen = inlen * 2; out = mymalloc(outlen + 1); if(out == NULL) { snprintf(errbuf, errlen, "Out of memory"); inflateEnd(&z); buf_release(bin); return NULL; } while(1) { if(outlen - z.total_out == 0) { outlen *= 2; out = realloc(out, outlen+1); } z.next_out = out + z.total_out; z.avail_out = outlen - z.total_out; r = inflate(&z, 0); if(r == Z_STREAM_END) break; if(r != Z_OK) { snprintf(errbuf, errlen, "inflate: %s", z.msg); inflateEnd(&z); free(out); buf_release(bin); return NULL; } } out[z.total_out] = 0; inflateEnd(&z); buf_release(bin); return buf_create_and_adopt(z.total_out, out, &free); }