2 * Copyright (c) 2015 Ludmila Glinskih
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include "libavutil/adler32.h"
28 #include "libavutil/mem.h"
29 #include "libavcodec/avcodec.h"
30 #include "libavformat/avformat.h"
31 #include "libavutil/imgutils.h"
36 int number_of_elements
;
38 static int add_crc_to_array(uint32_t crc
, int64_t pts
)
40 if (size_of_array
<= number_of_elements
) {
41 if (size_of_array
== 0)
44 crc_array
= av_realloc_f(crc_array
, size_of_array
, sizeof(uint32_t));
45 pts_array
= av_realloc_f(pts_array
, size_of_array
, sizeof(int64_t));
46 if ((crc_array
== NULL
) || (pts_array
== NULL
)) {
47 av_log(NULL
, AV_LOG_ERROR
, "Can't allocate array to store crcs\n");
48 return AVERROR(ENOMEM
);
51 crc_array
[number_of_elements
] = crc
;
52 pts_array
[number_of_elements
] = pts
;
57 static int compare_crc_in_array(uint32_t crc
, int64_t pts
)
60 for (i
= 0; i
< number_of_elements
; i
++) {
61 if (pts_array
[i
] == pts
) {
62 if (crc_array
[i
] == crc
) {
63 printf("Comparing 0x%08"PRIx32
" %"PRId64
" %d is OK\n", crc
, pts
, i
);
67 av_log(NULL
, AV_LOG_ERROR
, "Incorrect crc of a frame after seeking\n");
72 av_log(NULL
, AV_LOG_ERROR
, "Incorrect pts of a frame after seeking\n");
76 static int compute_crc_of_packets(AVFormatContext
*fmt_ctx
, int video_stream
,
77 AVCodecContext
*ctx
, AVPacket
*pkt
, AVFrame
*fr
,
78 uint64_t ts_start
, uint64_t ts_end
, int no_seeking
)
80 int number_of_written_bytes
;
86 byte_buffer_size
= av_image_get_buffer_size(ctx
->pix_fmt
, ctx
->width
, ctx
->height
, 16);
87 byte_buffer
= av_malloc(byte_buffer_size
);
89 av_log(NULL
, AV_LOG_ERROR
, "Can't allocate buffer\n");
90 return AVERROR(ENOMEM
);
94 result
= av_seek_frame(fmt_ctx
, video_stream
, ts_start
, AVSEEK_FLAG_ANY
);
95 printf("Seeking to %"PRId64
", computing crc for frames with pts < %"PRId64
"\n", ts_start
, ts_end
);
97 av_log(NULL
, AV_LOG_ERROR
, "Error in seeking\n");
100 avcodec_flush_buffers(ctx
);
104 result
= av_read_frame(fmt_ctx
, pkt
);
105 if (result
>= 0 && pkt
->stream_index
!= video_stream
) {
106 av_packet_unref(pkt
);
111 result
= avcodec_send_packet(ctx
, NULL
);
113 if (pkt
->pts
== AV_NOPTS_VALUE
) {
114 av_log(NULL
, AV_LOG_ERROR
, "Error: frames doesn't have pts values\n");
117 result
= avcodec_send_packet(ctx
, pkt
);
120 av_packet_unref(pkt
);
123 av_log(NULL
, AV_LOG_ERROR
, "Error submitting a packet for decoding\n");
127 while (result
>= 0) {
128 result
= avcodec_receive_frame(ctx
, fr
);
129 if (result
== AVERROR_EOF
)
131 else if (result
== AVERROR(EAGAIN
)) {
134 } else if (result
< 0) {
135 av_log(NULL
, AV_LOG_ERROR
, "Error decoding frame\n");
139 number_of_written_bytes
= av_image_copy_to_buffer(byte_buffer
, byte_buffer_size
,
140 (const uint8_t* const *)fr
->data
, (const int*) fr
->linesize
,
141 ctx
->pix_fmt
, ctx
->width
, ctx
->height
, 1);
142 if (number_of_written_bytes
< 0) {
143 av_log(NULL
, AV_LOG_ERROR
, "Can't copy image to buffer\n");
144 return number_of_written_bytes
;
146 if ((!no_seeking
) && (fr
->pts
> ts_end
))
148 crc
= av_adler32_update(0, (const uint8_t*)byte_buffer
, number_of_written_bytes
);
149 printf("%10"PRId64
", 0x%08"PRIx32
"\n", fr
->pts
, crc
);
151 if (add_crc_to_array(crc
, fr
->pts
) < 0)
155 if (compare_crc_in_array(crc
, fr
->pts
) < 0)
160 } while (result
>= 0 && (no_seeking
|| (fr
->pts
+ fr
->duration
<= ts_end
)));
163 av_freep(&byte_buffer
);
168 static long int read_seek_range(const char *string_with_number
)
171 char *end_of_string
= NULL
;
172 number
= strtol(string_with_number
, &end_of_string
, 10);
173 if ((strlen(string_with_number
) != end_of_string
- string_with_number
) || (number
< 0)) {
174 av_log(NULL
, AV_LOG_ERROR
, "Incorrect input ranges of seeking\n");
177 else if ((number
== LONG_MAX
) || (number
== LONG_MIN
)) {
178 if (errno
== ERANGE
) {
179 av_log(NULL
, AV_LOG_ERROR
, "Incorrect input ranges of seeking\n");
186 static int seek_test(const char *input_filename
, const char *start
, const char *end
)
188 const AVCodec
*codec
= NULL
;
189 AVCodecContext
*ctx
= NULL
;
190 AVCodecParameters
*origin_par
= NULL
;
191 AVPacket
*pkt
= NULL
;
193 AVFormatContext
*fmt_ctx
= NULL
;
197 long int start_ts
, end_ts
;
200 number_of_elements
= 0;
204 result
= avformat_open_input(&fmt_ctx
, input_filename
, NULL
, NULL
);
206 av_log(NULL
, AV_LOG_ERROR
, "Can't open file\n");
210 result
= avformat_find_stream_info(fmt_ctx
, NULL
);
212 av_log(NULL
, AV_LOG_ERROR
, "Can't get stream info\n");
216 start_ts
= read_seek_range(start
);
217 end_ts
= read_seek_range(end
);
218 if ((start_ts
< 0) || (end_ts
< 0)) {
223 //TODO: add ability to work with audio format
224 video_stream
= av_find_best_stream(fmt_ctx
, AVMEDIA_TYPE_VIDEO
, -1, -1, NULL
, 0);
225 if (video_stream
< 0) {
226 av_log(NULL
, AV_LOG_ERROR
, "Can't find video stream in input file\n");
227 result
= video_stream
;
231 origin_par
= fmt_ctx
->streams
[video_stream
]->codecpar
;
233 codec
= avcodec_find_decoder(origin_par
->codec_id
);
235 av_log(NULL
, AV_LOG_ERROR
, "Can't find decoder\n");
236 result
= AVERROR_DECODER_NOT_FOUND
;
240 ctx
= avcodec_alloc_context3(codec
);
242 av_log(NULL
, AV_LOG_ERROR
, "Can't allocate decoder context\n");
243 result
= AVERROR(ENOMEM
);
247 result
= avcodec_parameters_to_context(ctx
, origin_par
);
249 av_log(NULL
, AV_LOG_ERROR
, "Can't copy decoder context\n");
253 result
= avcodec_open2(ctx
, codec
, NULL
);
255 av_log(ctx
, AV_LOG_ERROR
, "Can't open decoder\n");
259 fr
= av_frame_alloc();
261 av_log(NULL
, AV_LOG_ERROR
, "Can't allocate frame\n");
262 result
= AVERROR(ENOMEM
);
266 pkt
= av_packet_alloc();
268 av_log(NULL
, AV_LOG_ERROR
, "Cannot allocate packet\n");
269 result
= AVERROR(ENOMEM
);
273 result
= compute_crc_of_packets(fmt_ctx
, video_stream
, ctx
, pkt
, fr
, 0, 0, 1);
277 for (i
= start_ts
; i
< end_ts
; i
+= 100) {
278 for (j
= i
+ 100; j
< end_ts
; j
+= 100) {
279 result
= compute_crc_of_packets(fmt_ctx
, video_stream
, ctx
, pkt
, fr
, i
, j
, 0);
286 av_freep(&crc_array
);
287 av_freep(&pts_array
);
288 av_packet_free(&pkt
);
290 avformat_close_input(&fmt_ctx
);
291 avcodec_free_context(&ctx
);
295 int main(int argc
, char **argv
)
298 av_log(NULL
, AV_LOG_ERROR
, "Incorrect input\n");
302 if (seek_test(argv
[1], argv
[2], argv
[3]) != 0)