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 }