Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 <libavformat/avformat.h> | |
26 | ||
27 | static AVFormatContext *fmt_ctx = NULL; | |
28 | static AVCodecContext *video_dec_ctx = NULL; | |
29 | static AVStream *video_stream = NULL; | |
30 | static const char *src_filename = NULL; | |
31 | ||
32 | static int video_stream_idx = -1; | |
33 | static AVFrame *frame = NULL; | |
34 | static AVPacket pkt; | |
35 | static int video_frame_count = 0; | |
36 | ||
37 | static int decode_packet(int *got_frame, int cached) | |
38 | { | |
39 | int decoded = pkt.size; | |
40 | ||
41 | *got_frame = 0; | |
42 | ||
43 | if (pkt.stream_index == video_stream_idx) { | |
44 | int ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt); | |
45 | if (ret < 0) { | |
46 | fprintf(stderr, "Error decoding video frame (%s)\n", av_err2str(ret)); | |
47 | return ret; | |
48 | } | |
49 | ||
50 | if (*got_frame) { | |
51 | int i; | |
52 | AVFrameSideData *sd; | |
53 | ||
54 | video_frame_count++; | |
55 | sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS); | |
56 | if (sd) { | |
57 | const AVMotionVector *mvs = (const AVMotionVector *)sd->data; | |
58 | for (i = 0; i < sd->size / sizeof(*mvs); i++) { | |
59 | const AVMotionVector *mv = &mvs[i]; | |
60 | printf("%d,%2d,%2d,%2d,%4d,%4d,%4d,%4d,0x%"PRIx64"\n", | |
61 | video_frame_count, mv->source, | |
62 | mv->w, mv->h, mv->src_x, mv->src_y, | |
63 | mv->dst_x, mv->dst_y, mv->flags); | |
64 | } | |
65 | } | |
66 | } | |
67 | } | |
68 | ||
69 | return decoded; | |
70 | } | |
71 | ||
72 | static int open_codec_context(int *stream_idx, | |
73 | AVFormatContext *fmt_ctx, enum AVMediaType type) | |
74 | { | |
75 | int ret; | |
76 | AVStream *st; | |
77 | AVCodecContext *dec_ctx = NULL; | |
78 | AVCodec *dec = NULL; | |
79 | AVDictionary *opts = NULL; | |
80 | ||
81 | ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); | |
82 | if (ret < 0) { | |
83 | fprintf(stderr, "Could not find %s stream in input file '%s'\n", | |
84 | av_get_media_type_string(type), src_filename); | |
85 | return ret; | |
86 | } else { | |
87 | *stream_idx = ret; | |
88 | st = fmt_ctx->streams[*stream_idx]; | |
89 | ||
90 | /* find decoder for the stream */ | |
91 | dec_ctx = st->codec; | |
92 | dec = avcodec_find_decoder(dec_ctx->codec_id); | |
93 | if (!dec) { | |
94 | fprintf(stderr, "Failed to find %s codec\n", | |
95 | av_get_media_type_string(type)); | |
96 | return AVERROR(EINVAL); | |
97 | } | |
98 | ||
99 | /* Init the video decoder */ | |
100 | av_dict_set(&opts, "flags2", "+export_mvs", 0); | |
101 | if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) { | |
102 | fprintf(stderr, "Failed to open %s codec\n", | |
103 | av_get_media_type_string(type)); | |
104 | return ret; | |
105 | } | |
106 | } | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | int main(int argc, char **argv) | |
112 | { | |
113 | int ret = 0, got_frame; | |
114 | ||
115 | if (argc != 2) { | |
116 | fprintf(stderr, "Usage: %s <video>\n", argv[0]); | |
117 | exit(1); | |
118 | } | |
119 | src_filename = argv[1]; | |
120 | ||
121 | av_register_all(); | |
122 | ||
123 | if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) { | |
124 | fprintf(stderr, "Could not open source file %s\n", src_filename); | |
125 | exit(1); | |
126 | } | |
127 | ||
128 | if (avformat_find_stream_info(fmt_ctx, NULL) < 0) { | |
129 | fprintf(stderr, "Could not find stream information\n"); | |
130 | exit(1); | |
131 | } | |
132 | ||
133 | if (open_codec_context(&video_stream_idx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) { | |
134 | video_stream = fmt_ctx->streams[video_stream_idx]; | |
135 | video_dec_ctx = video_stream->codec; | |
136 | } | |
137 | ||
138 | av_dump_format(fmt_ctx, 0, src_filename, 0); | |
139 | ||
140 | if (!video_stream) { | |
141 | fprintf(stderr, "Could not find video stream in the input, aborting\n"); | |
142 | ret = 1; | |
143 | goto end; | |
144 | } | |
145 | ||
146 | frame = av_frame_alloc(); | |
147 | if (!frame) { | |
148 | fprintf(stderr, "Could not allocate frame\n"); | |
149 | ret = AVERROR(ENOMEM); | |
150 | goto end; | |
151 | } | |
152 | ||
153 | printf("framenum,source,blockw,blockh,srcx,srcy,dstx,dsty,flags\n"); | |
154 | ||
155 | /* initialize packet, set data to NULL, let the demuxer fill it */ | |
156 | av_init_packet(&pkt); | |
157 | pkt.data = NULL; | |
158 | pkt.size = 0; | |
159 | ||
160 | /* read frames from the file */ | |
161 | while (av_read_frame(fmt_ctx, &pkt) >= 0) { | |
162 | AVPacket orig_pkt = pkt; | |
163 | do { | |
164 | ret = decode_packet(&got_frame, 0); | |
165 | if (ret < 0) | |
166 | break; | |
167 | pkt.data += ret; | |
168 | pkt.size -= ret; | |
169 | } while (pkt.size > 0); | |
170 | av_free_packet(&orig_pkt); | |
171 | } | |
172 | ||
173 | /* flush cached frames */ | |
174 | pkt.data = NULL; | |
175 | pkt.size = 0; | |
176 | do { | |
177 | decode_packet(&got_frame, 1); | |
178 | } while (got_frame); | |
179 | ||
180 | end: | |
181 | avcodec_close(video_dec_ctx); | |
182 | avformat_close_input(&fmt_ctx); | |
183 | av_frame_free(&frame); | |
184 | return ret < 0; | |
185 | } |