blob: 7b0d3d2ca8e1b1f9b9f03f901cfb367c6a830fe5 [file] [log] [blame]
Stefan Holmerd04f8522011-05-02 15:30:51 +02001@TEMPLATE decoder_tmpl.c
2Decode With Partial Drops Example
3=========================
4~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION
5This is an example utility which drops a series of frames (or parts of frames),
6as specified on the command line. This is useful for observing the error
7recovery features of the codec.
8~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION
9
10~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES
11#include <time.h>
12~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES
13
14~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS
15struct parsed_header
16{
17 char key_frame;
18 int version;
19 char show_frame;
20 int first_part_size;
21};
22
23int next_packet(struct parsed_header* hdr, int pos, int length, int mtu)
24{
25 int size = 0;
26 int remaining = length - pos;
27 /* Uncompressed part is 3 bytes for P frames and 10 bytes for I frames */
28 int uncomp_part_size = (hdr->key_frame ? 10 : 3);
29 /* number of bytes yet to send from header and the first partition */
30 int remainFirst = uncomp_part_size + hdr->first_part_size - pos;
31 if (remainFirst > 0)
32 {
33 if (remainFirst <= mtu)
34 {
35 size = remainFirst;
36 }
37 else
38 {
39 size = mtu;
40 }
41
42 return size;
43 }
44
45 /* second partition; just slot it up according to MTU */
46 if (remaining <= mtu)
47 {
48 size = remaining;
49 return size;
50 }
51 return mtu;
52}
53
54void throw_packets(unsigned char* frame, int* size, int loss_rate,
55 int* thrown, int* kept)
56{
57 unsigned char loss_frame[256*1024];
58 int pkg_size = 1;
59 int pos = 0;
60 int loss_pos = 0;
61 struct parsed_header hdr;
62 unsigned int tmp;
63 int mtu = 1500;
64
65 if (*size < 3)
66 {
67 return;
68 }
69 putc('|', stdout);
70 /* parse uncompressed 3 bytes */
71 tmp = (frame[2] << 16) | (frame[1] << 8) | frame[0];
72 hdr.key_frame = !(tmp & 0x1); /* inverse logic */
73 hdr.version = (tmp >> 1) & 0x7;
74 hdr.show_frame = (tmp >> 4) & 0x1;
75 hdr.first_part_size = (tmp >> 5) & 0x7FFFF;
76
77 /* don't drop key frames */
78 if (hdr.key_frame)
79 {
80 int i;
81 *kept = *size/mtu + ((*size % mtu > 0) ? 1 : 0); /* approximate */
82 for (i=0; i < *kept; i++)
83 putc('.', stdout);
84 return;
85 }
86
87 while ((pkg_size = next_packet(&hdr, pos, *size, mtu)) > 0)
88 {
89 int loss_event = ((rand() + 1.0)/(RAND_MAX + 1.0) < loss_rate/100.0);
90 if (*thrown == 0 && !loss_event)
91 {
92 memcpy(loss_frame + loss_pos, frame + pos, pkg_size);
93 loss_pos += pkg_size;
94 (*kept)++;
95 putc('.', stdout);
96 }
97 else
98 {
99 (*thrown)++;
100 putc('X', stdout);
101 }
102 pos += pkg_size;
103 }
104 memcpy(frame, loss_frame, loss_pos);
105 memset(frame + loss_pos, 0, *size - loss_pos);
106 *size = loss_pos;
107}
108~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS
109
110~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT
111/* Initialize codec */
112flags = VPX_CODEC_USE_ERROR_CONCEALMENT;
Stefan Holmerba0822b2011-06-16 11:44:50 +0200113res = vpx_codec_dec_init(&codec, interface, &dec_cfg, flags);
Stefan Holmerd04f8522011-05-02 15:30:51 +0200114if(res)
115 die_codec(&codec, "Failed to initialize decoder");
116
117~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT
118
119Usage
120-----
121This example adds a single argument to the `simple_decoder` example,
122which specifies the range or pattern of frames to drop. The parameter is
123parsed as follows:
124
125~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE
Stefan Holmerba0822b2011-06-16 11:44:50 +0200126if(argc < 4 || argc > 6)
127 die("Usage: %s <infile> <outfile> [-t <num threads>] <N-M|N/M|L,S>\n",
128 argv[0]);
Stefan Holmerd04f8522011-05-02 15:30:51 +0200129{
130 char *nptr;
Stefan Holmerba0822b2011-06-16 11:44:50 +0200131 int arg_num = 3;
132 if (argc == 6 && strncmp(argv[arg_num++], "-t", 2) == 0)
133 dec_cfg.threads = strtol(argv[arg_num++], NULL, 0);
134 n = strtol(argv[arg_num], &nptr, 0);
Stefan Holmerd04f8522011-05-02 15:30:51 +0200135 mode = (*nptr == '\0' || *nptr == ',') ? 2 : (*nptr == '-') ? 1 : 0;
136
137 m = strtol(nptr+1, NULL, 0);
138 if((!n && !m) || (*nptr != '-' && *nptr != '/' &&
139 *nptr != '\0' && *nptr != ','))
140 die("Couldn't parse pattern %s\n", argv[3]);
141}
142seed = (m > 0) ? m : (unsigned int)time(NULL);
143srand(seed);thrown_frame = 0;
144printf("Seed: %u\n", seed);
Stefan Holmerba0822b2011-06-16 11:44:50 +0200145printf("Threads: %d\n", dec_cfg.threads);
Stefan Holmerd04f8522011-05-02 15:30:51 +0200146~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE
147
148
149Dropping A Range Of Frames
150--------------------------
151To drop a range of frames, specify the starting frame and the ending
152frame to drop, separated by a dash. The following command will drop
153frames 5 through 10 (base 1).
154
155 $ ./decode_with_partial_drops in.ivf out.i420 5-10
156
157
158Dropping A Pattern Of Frames
159----------------------------
160To drop a pattern of frames, specify the number of frames to drop and
161the number of frames after which to repeat the pattern, separated by
162a forward-slash. The following command will drop 3 of 7 frames.
163Specifically, it will decode 4 frames, then drop 3 frames, and then
164repeat.
165
166 $ ./decode_with_partial_drops in.ivf out.i420 3/7
167
168Dropping Random Parts Of Frames
169-------------------------------
170A third argument tuple is available to split the frame into 1500 bytes pieces
171and randomly drop pieces rather than frames. The frame will be split at
172partition boundaries where possible. The following example will seed the RNG
173with the seed 123 and drop approximately 5% of the pieces. Pieces which
174are depending on an already dropped piece will also be dropped.
175
176 $ ./decode_with_partial_drops in.ivf out.i420 5,123
177
178
179Extra Variables
180---------------
181This example maintains the pattern passed on the command line in the
182`n`, `m`, and `is_range` variables:
183
184~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS
185int n, m, mode;
186unsigned int seed;
187int thrown=0, kept=0;
188int thrown_frame=0, kept_frame=0;
Stefan Holmerba0822b2011-06-16 11:44:50 +0200189vpx_codec_dec_cfg_t dec_cfg = {0};
Stefan Holmerd04f8522011-05-02 15:30:51 +0200190~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS
191
192
193Making The Drop Decision
194------------------------
195The example decides whether to drop the frame based on the current
196frame number, immediately before decoding the frame.
197
198~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE
199/* Decide whether to throw parts of the frame or the whole frame
200 depending on the drop mode */
201thrown_frame = 0;
202kept_frame = 0;
203switch (mode)
204{
205case 0:
206 if (m - (frame_cnt-1)%m <= n)
207 {
208 frame_sz = 0;
209 }
210 break;
211case 1:
212 if (frame_cnt >= n && frame_cnt <= m)
213 {
214 frame_sz = 0;
215 }
216 break;
217case 2:
218 throw_packets(frame, &frame_sz, n, &thrown_frame, &kept_frame);
219 break;
220default: break;
221}
222if (mode < 2)
223{
224 if (frame_sz == 0)
225 {
226 putc('X', stdout);
227 thrown_frame++;
228 }
229 else
230 {
231 putc('.', stdout);
232 kept_frame++;
233 }
234}
235thrown += thrown_frame;
236kept += kept_frame;
237fflush(stdout);
238~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE