1/* 2 * Copyright (c) 2012 Stefano Sabatini 3 * Copyright (c) 2014 Clément Bœsch 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 * THE SOFTWARE. 22 */ 23 24#include <libavutil/motion_vector.h> 25#include <libavcodec/avcodec.h> 26#include <libavformat/avformat.h> 27 28static AVFormatContext *fmt_ctx = NULL; 29static AVCodecContext *video_dec_ctx = NULL; 30static AVStream *video_stream = NULL; 31static const char *src_filename = NULL; 32 33static int video_stream_idx = -1; 34static AVFrame *frame = NULL; 35static int video_frame_count = 0; 36 37static int decode_packet(const AVPacket *pkt) 38{ 39 int ret = avcodec_send_packet(video_dec_ctx, pkt); 40 if (ret < 0) { 41 fprintf(stderr, "Error while sending a packet to the decoder: %s\n", av_err2str(ret)); 42 return ret; 43 } 44 45 while (ret >= 0) { 46 ret = avcodec_receive_frame(video_dec_ctx, frame); 47 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 48 break; 49 } else if (ret < 0) { 50 fprintf(stderr, "Error while receiving a frame from the decoder: %s\n", av_err2str(ret)); 51 return ret; 52 } 53 54 if (ret >= 0) { 55 int i; 56 AVFrameSideData *sd; 57 58 video_frame_count++; 59 sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS); 60 if (sd) { 61 const AVMotionVector *mvs = (const AVMotionVector *)sd->data; 62 for (i = 0; i < sd->size / sizeof(*mvs); i++) { 63 const AVMotionVector *mv = &mvs[i]; 64 printf("%d,%2d,%2d,%2d,%4d,%4d,%4d,%4d,0x%"PRIx64"\n", 65 video_frame_count, mv->source, 66 mv->w, mv->h, mv->src_x, mv->src_y, 67 mv->dst_x, mv->dst_y, mv->flags); 68 } 69 } 70 av_frame_unref(frame); 71 } 72 } 73 74 return 0; 75} 76 77static int open_codec_context(AVFormatContext *fmt_ctx, enum AVMediaType type) 78{ 79 int ret; 80 AVStream *st; 81 AVCodecContext *dec_ctx = NULL; 82 const AVCodec *dec = NULL; 83 AVDictionary *opts = NULL; 84 85 ret = av_find_best_stream(fmt_ctx, type, -1, -1, &dec, 0); 86 if (ret < 0) { 87 fprintf(stderr, "Could not find %s stream in input file '%s'\n", 88 av_get_media_type_string(type), src_filename); 89 return ret; 90 } else { 91 int stream_idx = ret; 92 st = fmt_ctx->streams[stream_idx]; 93 94 dec_ctx = avcodec_alloc_context3(dec); 95 if (!dec_ctx) { 96 fprintf(stderr, "Failed to allocate codec\n"); 97 return AVERROR(EINVAL); 98 } 99 100 ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); 101 if (ret < 0) { 102 fprintf(stderr, "Failed to copy codec parameters to codec context\n"); 103 return ret; 104 } 105 106 /* Init the video decoder */ 107 av_dict_set(&opts, "flags2", "+export_mvs", 0); 108 ret = avcodec_open2(dec_ctx, dec, &opts); 109 av_dict_free(&opts); 110 if (ret < 0) { 111 fprintf(stderr, "Failed to open %s codec\n", 112 av_get_media_type_string(type)); 113 return ret; 114 } 115 116 video_stream_idx = stream_idx; 117 video_stream = fmt_ctx->streams[video_stream_idx]; 118 video_dec_ctx = dec_ctx; 119 } 120 121 return 0; 122} 123 124int main(int argc, char **argv) 125{ 126 int ret = 0; 127 AVPacket *pkt = NULL; 128 129 if (argc != 2) { 130 fprintf(stderr, "Usage: %s <video>\n", argv[0]); 131 exit(1); 132 } 133 src_filename = argv[1]; 134 135 if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) { 136 fprintf(stderr, "Could not open source file %s\n", src_filename); 137 exit(1); 138 } 139 140 if (avformat_find_stream_info(fmt_ctx, NULL) < 0) { 141 fprintf(stderr, "Could not find stream information\n"); 142 exit(1); 143 } 144 145 open_codec_context(fmt_ctx, AVMEDIA_TYPE_VIDEO); 146 147 av_dump_format(fmt_ctx, 0, src_filename, 0); 148 149 if (!video_stream) { 150 fprintf(stderr, "Could not find video stream in the input, aborting\n"); 151 ret = 1; 152 goto end; 153 } 154 155 frame = av_frame_alloc(); 156 if (!frame) { 157 fprintf(stderr, "Could not allocate frame\n"); 158 ret = AVERROR(ENOMEM); 159 goto end; 160 } 161 162 pkt = av_packet_alloc(); 163 if (!pkt) { 164 fprintf(stderr, "Could not allocate AVPacket\n"); 165 ret = AVERROR(ENOMEM); 166 goto end; 167 } 168 169 printf("framenum,source,blockw,blockh,srcx,srcy,dstx,dsty,flags\n"); 170 171 /* read frames from the file */ 172 while (av_read_frame(fmt_ctx, pkt) >= 0) { 173 if (pkt->stream_index == video_stream_idx) 174 ret = decode_packet(pkt); 175 av_packet_unref(pkt); 176 if (ret < 0) 177 break; 178 } 179 180 /* flush cached frames */ 181 decode_packet(NULL); 182 183end: 184 avcodec_free_context(&video_dec_ctx); 185 avformat_close_input(&fmt_ctx); 186 av_frame_free(&frame); 187 av_packet_free(&pkt); 188 return ret < 0; 189} 190