Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2001 Fabrice Bellard | ||
3 | * | ||
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: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
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 | ||
20 | * THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #define MAX_SLICES 8 | ||
24 | |||
25 | #include "config.h" | ||
26 | |||
27 | #include <stdio.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <string.h> | ||
30 | |||
31 | #if HAVE_UNISTD_H | ||
32 | #include <unistd.h> | ||
33 | #endif | ||
34 | #if HAVE_IO_H | ||
35 | #include <io.h> | ||
36 | #endif | ||
37 | #include <sys/types.h> | ||
38 | #include <sys/stat.h> | ||
39 | #include <fcntl.h> | ||
40 | |||
41 | #include "libavcodec/avcodec.h" | ||
42 | #include "libavutil/mem.h" | ||
43 | #include "libavutil/pixdesc.h" | ||
44 | #include "libavutil/hash.h" | ||
45 | #include "libavutil/bswap.h" | ||
46 | |||
47 | static int header = 0; | ||
48 | |||
49 | 757 | static int decode(AVCodecContext *dec_ctx, AVFrame *frame, | |
50 | AVPacket *pkt) | ||
51 | { | ||
52 | static uint64_t frame_cnt = 0; | ||
53 | int ret; | ||
54 | |||
55 | 757 | ret = avcodec_send_packet(dec_ctx, pkt); | |
56 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 757 times.
|
757 | if (ret < 0) { |
57 | ✗ | fprintf(stderr, "Error sending a packet for decoding: %s\n", av_err2str(ret)); | |
58 | ✗ | return ret; | |
59 | } | ||
60 | |||
61 |
1/2✓ Branch 0 taken 1057 times.
✗ Branch 1 not taken.
|
1057 | while (ret >= 0) { |
62 | const AVPixFmtDescriptor *desc; | ||
63 | char sum[AV_HASH_MAX_SIZE * 2 + 1]; | ||
64 | struct AVHashContext *hash; | ||
65 | |||
66 | 1057 | ret = avcodec_receive_frame(dec_ctx, frame); | |
67 |
4/4✓ Branch 0 taken 301 times.
✓ Branch 1 taken 756 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 300 times.
|
1057 | if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { |
68 | 757 | return 0; | |
69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
|
300 | } else if (ret < 0) { |
70 | ✗ | fprintf(stderr, "Error during decoding: %s\n", av_err2str(ret)); | |
71 | ✗ | return ret; | |
72 | } | ||
73 | |||
74 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 299 times.
|
300 | if (!header) { |
75 | 1 | printf( | |
76 | "#format: frame checksums\n" | ||
77 | "#version: 2\n" | ||
78 | "#hash: MD5\n" | ||
79 | "#tb 0: 1/30\n" | ||
80 | "#media_type 0: video\n" | ||
81 | "#codec_id 0: rawvideo\n" | ||
82 | "#dimensions 0: 352x288\n" | ||
83 | "#sar 0: 128/117\n" | ||
84 | "#stream#, dts, pts, duration, size, hash\n"); | ||
85 | 1 | header = 1; | |
86 | } | ||
87 | 300 | desc = av_pix_fmt_desc_get(dec_ctx->pix_fmt); | |
88 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 300 times.
|
300 | if ((ret = av_hash_alloc(&hash, "md5")) < 0) { |
89 | ✗ | return ret; | |
90 | } | ||
91 | 300 | av_hash_init(hash); | |
92 | |||
93 |
2/2✓ Branch 0 taken 86400 times.
✓ Branch 1 taken 300 times.
|
86700 | for (int i = 0; i < frame->height; i++) |
94 | 86400 | av_hash_update(hash, &frame->data[0][i * frame->linesize[0]], frame->width); | |
95 |
2/2✓ Branch 0 taken 43200 times.
✓ Branch 1 taken 300 times.
|
43500 | for (int i = 0; i < frame->height >> desc->log2_chroma_h; i++) |
96 | 43200 | av_hash_update(hash, &frame->data[1][i * frame->linesize[1]], frame->width >> desc->log2_chroma_w); | |
97 |
2/2✓ Branch 0 taken 43200 times.
✓ Branch 1 taken 300 times.
|
43500 | for (int i = 0; i < frame->height >> desc->log2_chroma_h; i++) |
98 | 43200 | av_hash_update(hash, &frame->data[2][i * frame->linesize[2]], frame->width >> desc->log2_chroma_w); | |
99 | |||
100 | 300 | av_hash_final_hex(hash, sum, av_hash_get_size(hash) * 2 + 1); | |
101 | 300 | printf("0, %10"PRId64", %10"PRId64", 1, %8d, %s\n", | |
102 | frame_cnt, frame_cnt, | ||
103 | 300 | (frame->width * frame->height + 2 * (frame->height >> desc->log2_chroma_h) * (frame->width >> desc->log2_chroma_w)), sum); | |
104 | 300 | frame_cnt += 1; | |
105 | 300 | av_hash_freep(&hash); | |
106 | } | ||
107 | ✗ | return 0; | |
108 | } | ||
109 | |||
110 | 1 | int main(int argc, char **argv) | |
111 | { | ||
112 | 1 | const AVCodec *codec = NULL; | |
113 | 1 | AVCodecContext *c = NULL; | |
114 | 1 | AVFrame *frame = NULL; | |
115 | unsigned int threads; | ||
116 | AVPacket *pkt; | ||
117 | 1 | FILE *file = NULL; | |
118 | 1 | char * nal = NULL; | |
119 | 1 | int nals = 0, ret = 0; | |
120 | char *p; | ||
121 | |||
122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (argc < 3) { |
123 | ✗ | fprintf(stderr, "Usage: %s <threads> <input file>\n", argv[0]); | |
124 | ✗ | return -1; | |
125 | } | ||
126 | |||
127 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!(threads = strtoul(argv[1], NULL, 0))) |
128 | ✗ | threads = 1; | |
129 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | else if (threads > MAX_SLICES) |
130 | ✗ | threads = MAX_SLICES; | |
131 | |||
132 | #ifdef _WIN32 | ||
133 | setmode(fileno(stdout), O_BINARY); | ||
134 | #endif | ||
135 | |||
136 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!(pkt = av_packet_alloc())) { |
137 | ✗ | return -1; | |
138 | } | ||
139 | |||
140 | 1 | nal = av_malloc(MAX_SLICES * UINT16_MAX + AV_INPUT_BUFFER_PADDING_SIZE); | |
141 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!nal) |
142 | ✗ | goto err; | |
143 | 1 | p = nal; | |
144 | |||
145 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!(codec = avcodec_find_decoder(AV_CODEC_ID_H264))) { |
146 | ✗ | fprintf(stderr, "Codec not found\n"); | |
147 | ✗ | ret = -1; | |
148 | ✗ | goto err; | |
149 | } | ||
150 | |||
151 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!(c = avcodec_alloc_context3(codec))) { |
152 | ✗ | fprintf(stderr, "Could not allocate video codec context\n"); | |
153 | ✗ | ret = -1; | |
154 | ✗ | goto err; | |
155 | } | ||
156 | |||
157 | 1 | c->width = 352; | |
158 | 1 | c->height = 288; | |
159 | |||
160 | 1 | c->flags2 |= AV_CODEC_FLAG2_CHUNKS; | |
161 | 1 | c->thread_type = FF_THREAD_SLICE; | |
162 | 1 | c->thread_count = threads; | |
163 | |||
164 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if ((ret = avcodec_open2(c, codec, NULL)) < 0) { |
165 | ✗ | fprintf(stderr, "Could not open codec\n"); | |
166 | ✗ | goto err; | |
167 | } | ||
168 | |||
169 | #if HAVE_THREADS | ||
170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (c->active_thread_type != FF_THREAD_SLICE) { |
171 | ✗ | fprintf(stderr, "Couldn't activate slice threading: %d\n", c->active_thread_type); | |
172 | ✗ | ret = -1; | |
173 | ✗ | goto err; | |
174 | } | ||
175 | #else | ||
176 | fprintf(stderr, "WARN: not using threads, only checking decoding slice NALUs\n"); | ||
177 | #endif | ||
178 | |||
179 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!(frame = av_frame_alloc())) { |
180 | ✗ | fprintf(stderr, "Could not allocate video frame\n"); | |
181 | ✗ | ret = -1; | |
182 | ✗ | goto err; | |
183 | } | ||
184 | |||
185 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!(file = fopen(argv[2], "rb"))) { |
186 | ✗ | fprintf(stderr, "Couldn't open NALU file: %s\n", argv[2]); | |
187 | ✗ | ret = -1; | |
188 | ✗ | goto err; | |
189 | } | ||
190 | |||
191 | 1511 | while(1) { | |
192 | 1512 | uint16_t size = 0; | |
193 | 1512 | size_t ret = fread(&size, 1, sizeof(uint16_t), file); | |
194 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1511 times.
|
1512 | if (ret != sizeof(uint16_t)) |
195 | 1 | break; | |
196 | |||
197 | 1511 | size = av_be2ne16(size); | |
198 | 1511 | ret = fread(p, 1, size, file); | |
199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1511 times.
|
1511 | if (ret != size) { |
200 | ✗ | perror("Couldn't read data"); | |
201 | ✗ | goto err; | |
202 | } | ||
203 | 1511 | p += ret; | |
204 | |||
205 |
2/2✓ Branch 0 taken 755 times.
✓ Branch 1 taken 756 times.
|
1511 | if (++nals >= threads) { |
206 | 755 | int decret = 0; | |
207 | 755 | pkt->data = nal; | |
208 | 755 | pkt->size = p - nal; | |
209 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 755 times.
|
755 | if ((decret = decode(c, frame, pkt)) < 0) { |
210 | ✗ | goto err; | |
211 | } | ||
212 | 755 | memset(nal, 0, MAX_SLICES * UINT16_MAX + AV_INPUT_BUFFER_PADDING_SIZE); | |
213 | 755 | nals = 0; | |
214 | 755 | p = nal; | |
215 | } | ||
216 | } | ||
217 | |||
218 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (nals) { |
219 | 1 | pkt->data = nal; | |
220 | 1 | pkt->size = p - nal; | |
221 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if ((ret = decode(c, frame, pkt)) < 0) { |
222 | ✗ | goto err; | |
223 | } | ||
224 | } | ||
225 | |||
226 | 1 | ret = decode(c, frame, NULL); | |
227 | |||
228 | 1 | err: | |
229 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (nal) |
230 | 1 | av_free(nal); | |
231 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (file) |
232 | 1 | fclose(file); | |
233 | 1 | av_frame_free(&frame); | |
234 | 1 | avcodec_free_context(&c); | |
235 | 1 | av_packet_free(&pkt); | |
236 | |||
237 | 1 | return ret; | |
238 | } | ||
239 |