OLD | NEW |
(Empty) | |
| 1 @TEMPLATE decoder_tmpl.c |
| 2 Decode With Partial Drops Example |
| 3 ========================= |
| 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION |
| 5 This is an example utility which drops a series of frames (or parts of frames), |
| 6 as specified on the command line. This is useful for observing the error |
| 7 recovery features of the codec. |
| 8 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTRODUCTION |
| 9 |
| 10 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES |
| 11 #include <time.h> |
| 12 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_INCLUDES |
| 13 |
| 14 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS |
| 15 struct parsed_header |
| 16 { |
| 17 char key_frame; |
| 18 int version; |
| 19 char show_frame; |
| 20 int first_part_size; |
| 21 }; |
| 22 |
| 23 int 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 |
| 54 void 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 */ |
| 112 flags = VPX_CODEC_USE_ERROR_CONCEALMENT; |
| 113 res = vpx_codec_dec_init(&codec, interface, &dec_cfg, flags); |
| 114 if(res) |
| 115 die_codec(&codec, "Failed to initialize decoder"); |
| 116 |
| 117 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DEC_INIT |
| 118 |
| 119 Usage |
| 120 ----- |
| 121 This example adds a single argument to the `simple_decoder` example, |
| 122 which specifies the range or pattern of frames to drop. The parameter is |
| 123 parsed as follows: |
| 124 |
| 125 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE |
| 126 if(argc < 4 || argc > 6) |
| 127 die("Usage: %s <infile> <outfile> [-t <num threads>] <N-M|N/M|L,S>\n", |
| 128 argv[0]); |
| 129 { |
| 130 char *nptr; |
| 131 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); |
| 135 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 } |
| 142 seed = (m > 0) ? m : (unsigned int)time(NULL); |
| 143 srand(seed);thrown_frame = 0; |
| 144 printf("Seed: %u\n", seed); |
| 145 printf("Threads: %d\n", dec_cfg.threads); |
| 146 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ USAGE |
| 147 |
| 148 |
| 149 Dropping A Range Of Frames |
| 150 -------------------------- |
| 151 To drop a range of frames, specify the starting frame and the ending |
| 152 frame to drop, separated by a dash. The following command will drop |
| 153 frames 5 through 10 (base 1). |
| 154 |
| 155 $ ./decode_with_partial_drops in.ivf out.i420 5-10 |
| 156 |
| 157 |
| 158 Dropping A Pattern Of Frames |
| 159 ---------------------------- |
| 160 To drop a pattern of frames, specify the number of frames to drop and |
| 161 the number of frames after which to repeat the pattern, separated by |
| 162 a forward-slash. The following command will drop 3 of 7 frames. |
| 163 Specifically, it will decode 4 frames, then drop 3 frames, and then |
| 164 repeat. |
| 165 |
| 166 $ ./decode_with_partial_drops in.ivf out.i420 3/7 |
| 167 |
| 168 Dropping Random Parts Of Frames |
| 169 ------------------------------- |
| 170 A third argument tuple is available to split the frame into 1500 bytes pieces |
| 171 and randomly drop pieces rather than frames. The frame will be split at |
| 172 partition boundaries where possible. The following example will seed the RNG |
| 173 with the seed 123 and drop approximately 5% of the pieces. Pieces which |
| 174 are depending on an already dropped piece will also be dropped. |
| 175 |
| 176 $ ./decode_with_partial_drops in.ivf out.i420 5,123 |
| 177 |
| 178 |
| 179 Extra Variables |
| 180 --------------- |
| 181 This example maintains the pattern passed on the command line in the |
| 182 `n`, `m`, and `is_range` variables: |
| 183 |
| 184 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS |
| 185 int n, m, mode; |
| 186 unsigned int seed; |
| 187 int thrown=0, kept=0; |
| 188 int thrown_frame=0, kept_frame=0; |
| 189 vpx_codec_dec_cfg_t dec_cfg = {0}; |
| 190 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXTRA_VARS |
| 191 |
| 192 |
| 193 Making The Drop Decision |
| 194 ------------------------ |
| 195 The example decides whether to drop the frame based on the current |
| 196 frame 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 */ |
| 201 thrown_frame = 0; |
| 202 kept_frame = 0; |
| 203 switch (mode) |
| 204 { |
| 205 case 0: |
| 206 if (m - (frame_cnt-1)%m <= n) |
| 207 { |
| 208 frame_sz = 0; |
| 209 } |
| 210 break; |
| 211 case 1: |
| 212 if (frame_cnt >= n && frame_cnt <= m) |
| 213 { |
| 214 frame_sz = 0; |
| 215 } |
| 216 break; |
| 217 case 2: |
| 218 throw_packets(frame, &frame_sz, n, &thrown_frame, &kept_frame); |
| 219 break; |
| 220 default: break; |
| 221 } |
| 222 if (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 } |
| 235 thrown += thrown_frame; |
| 236 kept += kept_frame; |
| 237 fflush(stdout); |
| 238 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PRE_DECODE |
OLD | NEW |