sframe

Simple Frame — extract unique frames from videos
git clone git clone https://git.krisyotam.com/krisyotam/sframe.git
Log | Files | Refs | README | LICENSE

decode.c (3640B)


      1 /* See LICENSE file for copyright and license details. */
      2 
      3 #include <string.h>
      4 
      5 #include <libavformat/avformat.h>
      6 #include <libavcodec/avcodec.h>
      7 #include <libavutil/avutil.h>
      8 #include <libavutil/imgutils.h>
      9 #include <libswscale/swscale.h>
     10 
     11 #include "decode.h"
     12 #include "util.h"
     13 
     14 int
     15 dec_open(Decoder *d, const char *path)
     16 {
     17 	const AVCodec *codec;
     18 	AVStream *st;
     19 	int ret;
     20 	int i;
     21 
     22 	memset(d, 0, sizeof(*d));
     23 	d->stream_idx = -1;
     24 
     25 	ret = avformat_open_input(&d->fmt_ctx, path, NULL, NULL);
     26 	if (ret < 0) {
     27 		warn("cannot open '%s': %s", path, av_err2str(ret));
     28 		return -1;
     29 	}
     30 
     31 	ret = avformat_find_stream_info(d->fmt_ctx, NULL);
     32 	if (ret < 0) {
     33 		warn("no stream info in '%s'", path);
     34 		goto fail;
     35 	}
     36 
     37 	/* find first video stream */
     38 	for (i = 0; i < (int)d->fmt_ctx->nb_streams; i++) {
     39 		if (d->fmt_ctx->streams[i]->codecpar->codec_type
     40 		    == AVMEDIA_TYPE_VIDEO) {
     41 			d->stream_idx = i;
     42 			break;
     43 		}
     44 	}
     45 	if (d->stream_idx < 0) {
     46 		warn("no video stream in '%s'", path);
     47 		goto fail;
     48 	}
     49 
     50 	st = d->fmt_ctx->streams[d->stream_idx];
     51 	codec = avcodec_find_decoder(st->codecpar->codec_id);
     52 	if (!codec) {
     53 		warn("unsupported codec in '%s'", path);
     54 		goto fail;
     55 	}
     56 
     57 	d->codec_ctx = avcodec_alloc_context3(codec);
     58 	if (!d->codec_ctx) {
     59 		warn("cannot alloc codec context");
     60 		goto fail;
     61 	}
     62 
     63 	ret = avcodec_parameters_to_context(d->codec_ctx,
     64 	                                    st->codecpar);
     65 	if (ret < 0) {
     66 		warn("cannot copy codec params");
     67 		goto fail;
     68 	}
     69 
     70 	ret = avcodec_open2(d->codec_ctx, codec, NULL);
     71 	if (ret < 0) {
     72 		warn("cannot open codec: %s", av_err2str(ret));
     73 		goto fail;
     74 	}
     75 
     76 	d->width = d->codec_ctx->width;
     77 	d->height = d->codec_ctx->height;
     78 
     79 	/* scaler for 8x8 grayscale (perceptual hash) */
     80 	d->sws_gray = sws_getContext(
     81 		d->width, d->height, d->codec_ctx->pix_fmt,
     82 		8, 8, AV_PIX_FMT_GRAY8,
     83 		SWS_BILINEAR, NULL, NULL, NULL);
     84 	if (!d->sws_gray) {
     85 		warn("cannot create grayscale scaler");
     86 		goto fail;
     87 	}
     88 
     89 	/* scaler for full-res RGB (image saving) */
     90 	d->sws_rgb = sws_getContext(
     91 		d->width, d->height, d->codec_ctx->pix_fmt,
     92 		d->width, d->height, AV_PIX_FMT_RGB24,
     93 		SWS_BILINEAR, NULL, NULL, NULL);
     94 	if (!d->sws_rgb) {
     95 		warn("cannot create RGB scaler");
     96 		goto fail;
     97 	}
     98 
     99 	return 0;
    100 
    101 fail:
    102 	dec_close(d);
    103 	return -1;
    104 }
    105 
    106 int
    107 dec_read_frame(Decoder *d, AVFrame *frame)
    108 {
    109 	AVPacket *pkt;
    110 	int ret;
    111 
    112 	pkt = av_packet_alloc();
    113 	if (!pkt)
    114 		return -1;
    115 
    116 	for (;;) {
    117 		ret = av_read_frame(d->fmt_ctx, pkt);
    118 		if (ret < 0) {
    119 			av_packet_free(&pkt);
    120 			/* flush decoder */
    121 			avcodec_send_packet(d->codec_ctx, NULL);
    122 			ret = avcodec_receive_frame(d->codec_ctx,
    123 			                            frame);
    124 			return (ret == 0) ? 0 : -1;
    125 		}
    126 
    127 		if (pkt->stream_index != d->stream_idx) {
    128 			av_packet_unref(pkt);
    129 			continue;
    130 		}
    131 
    132 		ret = avcodec_send_packet(d->codec_ctx, pkt);
    133 		av_packet_unref(pkt);
    134 		if (ret < 0) {
    135 			av_packet_free(&pkt);
    136 			return -1;
    137 		}
    138 
    139 		ret = avcodec_receive_frame(d->codec_ctx, frame);
    140 		if (ret == AVERROR(EAGAIN))
    141 			continue;
    142 		if (ret < 0) {
    143 			av_packet_free(&pkt);
    144 			return -1;
    145 		}
    146 
    147 		av_packet_free(&pkt);
    148 		return 0;
    149 	}
    150 }
    151 
    152 double
    153 dec_frame_time(Decoder *d, AVFrame *frame)
    154 {
    155 	AVStream *st;
    156 	double tb;
    157 
    158 	st = d->fmt_ctx->streams[d->stream_idx];
    159 	tb = av_q2d(st->time_base);
    160 
    161 	if (frame->pts != AV_NOPTS_VALUE)
    162 		return frame->pts * tb;
    163 	if (frame->pkt_dts != AV_NOPTS_VALUE)
    164 		return frame->pkt_dts * tb;
    165 	return 0.0;
    166 }
    167 
    168 void
    169 dec_close(Decoder *d)
    170 {
    171 	if (d->sws_rgb)
    172 		sws_freeContext(d->sws_rgb);
    173 	if (d->sws_gray)
    174 		sws_freeContext(d->sws_gray);
    175 	if (d->codec_ctx)
    176 		avcodec_free_context(&d->codec_ctx);
    177 	if (d->fmt_ctx)
    178 		avformat_close_input(&d->fmt_ctx);
    179 	memset(d, 0, sizeof(*d));
    180 }