thumbnail.c 3.62 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#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[])
{
26
	int err, vidx;
Julian Rother's avatar
Julian Rother committed
27
	char *src, *tmp, *dest;
28 29 30 31 32 33 34
	AVFormatContext *demux, *mux;
	AVCodecContext *dec, *enc;
	AVPacket pkt;
	AVFrame *frame;
	if (argc != 5)
		return 1;
	av_register_all();
35
	avformat_network_init();
36
	init_env();
37
	init_avlogbuf();
38 39 40

	/* Prepare arguments */
	jobid = atoi(argv[1]);
41
	ping_job(jobid, "running", 0);
42 43 44 45
	if (jlookup(argv[4], "srcurl"))
		src = jstr(jlookup(argv[4], "srcurl"), 0);
	else
		src = buildpath(getenv(WORKER_RELEASED), jstr(jlookup(argv[4], "src"), 0));
46
	tmp = mprintf("%s/.tmp-%i", getenv(WORKER_TMP), jobid);
47 48
	dest = mprintf("%s/thumbnail/%s", getenv(WORKER_RELEASED),
			jstr(jlookup(argv[4], "filename"), "0"));
49 50 51

	/* Open src */
	demux = 0;
52 53
	if (err = avformat_open_input(&demux, src, 0, 0))
		job_failed("Opening input file failed: %s", av_err2str(err));
54 55
	avformat_find_stream_info(demux, 0);
	if ((vidx = av_find_best_stream(demux, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0)) < 0)
56
		job_failed("Could not find video stream in input file");
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
	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);
76 77
	if ((err = avformat_write_header(mux, 0)) < 0)
		job_failed("Writing temporary file failed: %s", av_err2str(err));
78 79

	/* Create thumbnail */
80 81
	if (!jlookup(argv[4], "srcurl"))
		av_seek_frame(demux, -1, (2L*demux->duration)/5L, 0);
82 83 84 85 86
	memset(&pkt, 0, sizeof(pkt));
	av_init_packet(&pkt);
	frame = av_frame_alloc();
	do
	{
87 88
		if (err = av_read_frame(demux, &pkt))
			job_failed("Reading frame failed: %s", av_err2str(err));
89 90 91 92 93 94 95 96 97 98 99 100 101 102
		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);
103 104
	if (err = av_write_trailer(mux))
		job_failed("Error writing trailer to temporary file: %s", av_err2str(err));
105
	avio_closep(&mux->pb);
Julian Rother's avatar
Julian Rother committed
106 107
	if (!filesize(tmp))
		job_failed("Sanity check failed: Output file is empty");
108
	if (rename(tmp, dest))
109
		job_failed("Overwriting output file failed: %s", strerror(errno));
110
	unlink(tmp);
111
	ping_job(jobid, "finished", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
112 113
	return 0;
}