Select Git revision
thumbnail.c
Julian Rother authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
thumbnail.c 3.62 KiB
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include "util.h"
AVFrame *scale_frame(AVFrame *frame, enum AVPixelFormat pix_fmt,
int width, int height)
{
AVFrame *scaled;
struct SwsContext *swsctx;
scaled = av_frame_alloc();
scaled->format = pix_fmt;
scaled->width = width;
scaled->height = height;
av_frame_get_buffer(scaled, 32);
swsctx = sws_getContext(frame->width, frame->height, frame->format,
scaled->width, scaled->height, scaled->format, 0, 0, 0, 0);
sws_scale(swsctx, (const uint8_t **) frame->data, frame->linesize, 0,
frame->height, scaled->data, scaled->linesize);
return scaled;
}
int main(int argc, char *argv[])
{
int err, vidx;
char *src, *tmp, *dest;
AVFormatContext *demux, *mux;
AVCodecContext *dec, *enc;
AVPacket pkt;
AVFrame *frame;
if (argc != 5)
return 1;
av_register_all();
avformat_network_init();
init_env();
init_avlogbuf();
/* Prepare arguments */
jobid = atoi(argv[1]);
ping_job(jobid, "running", 0);
if (jlookup(argv[4], "srcurl"))
src = jstr(jlookup(argv[4], "srcurl"), 0);
else
src = buildpath(getenv(WORKER_RELEASED), jstr(jlookup(argv[4], "src"), 0));
tmp = mprintf("%s/.tmp-%i", getenv(WORKER_TMP), jobid);
dest = mprintf("%s/thumbnail/%s", getenv(WORKER_RELEASED),
jstr(jlookup(argv[4], "filename"), "0"));
/* Open src */
demux = 0;
if (err = avformat_open_input(&demux, src, 0, 0))
job_failed("Opening input file failed: %s", av_err2str(err));
avformat_find_stream_info(demux, 0);
if ((vidx = av_find_best_stream(demux, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0)) < 0)
job_failed("Could not find video stream in input file");
dec = avcodec_alloc_context3(avcodec_find_decoder(demux->streams[vidx]->codecpar->codec_id));
avcodec_parameters_to_context(dec, demux->streams[vidx]->codecpar);
avcodec_open2(dec, dec->codec, 0);
/* Open temporary dest */
avformat_alloc_output_context2(&mux, 0, "image2", tmp);
avformat_new_stream(mux, 0);
enc = avcodec_alloc_context3(avcodec_find_encoder(AV_CODEC_ID_MJPEG));
enc->width = 640;
enc->height = (enc->width*dec->height)/dec->width;
if (enc->codec->pix_fmts)
enc->pix_fmt = enc->codec->pix_fmts[0];
else
enc->pix_fmt = dec->pix_fmt;
enc->sample_aspect_ratio = dec->sample_aspect_ratio;
enc->time_base = AV_TIME_BASE_Q;
avio_open(&mux->pb, tmp, AVIO_FLAG_WRITE);
avcodec_open2(enc, enc->codec, 0);
avcodec_parameters_from_context(mux->streams[0]->codecpar, enc);
if ((err = avformat_write_header(mux, 0)) < 0)
job_failed("Writing temporary file failed: %s", av_err2str(err));
/* Create thumbnail */
if (!jlookup(argv[4], "srcurl"))
av_seek_frame(demux, -1, (2L*demux->duration)/5L, 0);
memset(&pkt, 0, sizeof(pkt));
av_init_packet(&pkt);
frame = av_frame_alloc();
do
{
if (err = av_read_frame(demux, &pkt))
job_failed("Reading frame failed: %s", av_err2str(err));
if (pkt.stream_index == vidx)
avcodec_send_packet(dec, &pkt);
}
while (avcodec_receive_frame(dec, frame));
avcodec_send_frame(enc, scale_frame(frame, enc->pix_fmt, enc->width,
enc->height));
avcodec_send_frame(enc, 0);
while (!avcodec_receive_packet(enc, &pkt))
{
pkt.stream_index = 0;
pkt.pts = pkt.dts = 0;
av_interleaved_write_frame(mux, &pkt);
}
av_interleaved_write_frame(mux, 0);
if (err = av_write_trailer(mux))
job_failed("Error writing trailer to temporary file: %s", av_err2str(err));
avio_closep(&mux->pb);
if (!filesize(tmp))
job_failed("Sanity check failed: Output file is empty");
if (rename(tmp, dest))
job_failed("Overwriting output file failed: %s", strerror(errno));
unlink(tmp);
ping_job(jobid, "finished", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
return 0;
}